mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-26 11:14:04 +00:00
feat(internal_user_endpoints.py): emit audit log on /user/new
event
This commit is contained in:
parent
53f9df5506
commit
5cfae0e98a
4 changed files with 81 additions and 13 deletions
|
@ -5,13 +5,5 @@ model_list:
|
||||||
aws_region_name: "us-east-1"
|
aws_region_name: "us-east-1"
|
||||||
litellm_credential_name: "azure"
|
litellm_credential_name: "azure"
|
||||||
|
|
||||||
credential_list:
|
litellm_settings:
|
||||||
- credential_name: azure
|
store_audit_logs: true
|
||||||
credential_values:
|
|
||||||
api_key: os.environ/AZURE_API_KEY
|
|
||||||
api_base: os.environ/AZURE_API_BASE
|
|
||||||
credential_info:
|
|
||||||
description: "Azure API Key and Base URL"
|
|
||||||
type: "azure"
|
|
||||||
required: true
|
|
||||||
default: "azure"
|
|
||||||
|
|
|
@ -1584,7 +1584,7 @@ class NewOrganizationResponse(LiteLLM_OrganizationTable):
|
||||||
|
|
||||||
class LiteLLM_UserTable(LiteLLMPydanticObjectBase):
|
class LiteLLM_UserTable(LiteLLMPydanticObjectBase):
|
||||||
user_id: str
|
user_id: str
|
||||||
max_budget: Optional[float]
|
max_budget: Optional[float] = None
|
||||||
spend: float = 0.0
|
spend: float = 0.0
|
||||||
model_max_budget: Optional[Dict] = {}
|
model_max_budget: Optional[Dict] = {}
|
||||||
model_spend: Optional[Dict] = {}
|
model_spend: Optional[Dict] = {}
|
||||||
|
@ -1677,12 +1677,15 @@ class LiteLLM_ErrorLogs(LiteLLMPydanticObjectBase):
|
||||||
endTime: Union[str, datetime, None]
|
endTime: Union[str, datetime, None]
|
||||||
|
|
||||||
|
|
||||||
|
AUDIT_ACTIONS = Literal["created", "updated", "deleted", "blocked"]
|
||||||
|
|
||||||
|
|
||||||
class LiteLLM_AuditLogs(LiteLLMPydanticObjectBase):
|
class LiteLLM_AuditLogs(LiteLLMPydanticObjectBase):
|
||||||
id: str
|
id: str
|
||||||
updated_at: datetime
|
updated_at: datetime
|
||||||
changed_by: Optional[Any] = None
|
changed_by: Optional[Any] = None
|
||||||
changed_by_api_key: Optional[str] = None
|
changed_by_api_key: Optional[str] = None
|
||||||
action: Literal["created", "updated", "deleted", "blocked"]
|
action: AUDIT_ACTIONS
|
||||||
table_name: Literal[
|
table_name: Literal[
|
||||||
LitellmTableNames.TEAM_TABLE_NAME,
|
LitellmTableNames.TEAM_TABLE_NAME,
|
||||||
LitellmTableNames.USER_TABLE_NAME,
|
LitellmTableNames.USER_TABLE_NAME,
|
||||||
|
|
|
@ -53,8 +53,11 @@ def decrypt_value_helper(value: str):
|
||||||
# if it's not str - do not decrypt it, return the value
|
# if it's not str - do not decrypt it, return the value
|
||||||
return value
|
return value
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_stack()
|
||||||
verbose_proxy_logger.error(
|
verbose_proxy_logger.error(
|
||||||
f"Error decrypting value, Did your master_key/salt key change recently? : {value}\nError: {str(e)}\nSet permanent salt key - https://docs.litellm.ai/docs/proxy/prod#5-set-litellm-salt-key"
|
f"Error decrypting value, Did your master_key/salt key change recently? \nError: {str(e)}\nSet permanent salt key - https://docs.litellm.ai/docs/proxy/prod#5-set-litellm-salt-key"
|
||||||
)
|
)
|
||||||
# [Non-Blocking Exception. - this should not block decrypting other values]
|
# [Non-Blocking Exception. - this should not block decrypting other values]
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -29,12 +29,53 @@ from litellm.proxy.management_endpoints.key_management_endpoints import (
|
||||||
generate_key_helper_fn,
|
generate_key_helper_fn,
|
||||||
prepare_metadata_fields,
|
prepare_metadata_fields,
|
||||||
)
|
)
|
||||||
|
from litellm.proxy.management_helpers.audit_logs import create_audit_log_for_update
|
||||||
from litellm.proxy.management_helpers.utils import management_endpoint_wrapper
|
from litellm.proxy.management_helpers.utils import management_endpoint_wrapper
|
||||||
from litellm.proxy.utils import handle_exception_on_proxy
|
from litellm.proxy.utils import handle_exception_on_proxy
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
async def create_internal_user_audit_log(
|
||||||
|
user_id: str,
|
||||||
|
action: AUDIT_ACTIONS,
|
||||||
|
litellm_changed_by: Optional[str],
|
||||||
|
user_api_key_dict: UserAPIKeyAuth,
|
||||||
|
litellm_proxy_admin_name: Optional[str],
|
||||||
|
before_value: Optional[str] = None,
|
||||||
|
after_value: Optional[str] = None,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create an audit log for an internal user.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- user_id: str - The id of the user to create the audit log for.
|
||||||
|
- action: AUDIT_ACTIONS - The action to create the audit log for.
|
||||||
|
- user_row: LiteLLM_UserTable - The user row to create the audit log for.
|
||||||
|
- litellm_changed_by: Optional[str] - The user id of the user who is changing the user.
|
||||||
|
- user_api_key_dict: UserAPIKeyAuth - The user api key dictionary.
|
||||||
|
- litellm_proxy_admin_name: Optional[str] - The name of the proxy admin.
|
||||||
|
"""
|
||||||
|
if not litellm.store_audit_logs:
|
||||||
|
return
|
||||||
|
|
||||||
|
await create_audit_log_for_update(
|
||||||
|
request_data=LiteLLM_AuditLogs(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
updated_at=datetime.now(timezone.utc),
|
||||||
|
changed_by=litellm_changed_by
|
||||||
|
or user_api_key_dict.user_id
|
||||||
|
or litellm_proxy_admin_name,
|
||||||
|
changed_by_api_key=user_api_key_dict.api_key,
|
||||||
|
table_name=LitellmTableNames.USER_TABLE_NAME,
|
||||||
|
object_id=user_id,
|
||||||
|
action=action,
|
||||||
|
updated_values=after_value,
|
||||||
|
before_value=before_value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _update_internal_new_user_params(data_json: dict, data: NewUserRequest) -> dict:
|
def _update_internal_new_user_params(data_json: dict, data: NewUserRequest) -> dict:
|
||||||
if "user_id" in data_json and data_json["user_id"] is None:
|
if "user_id" in data_json and data_json["user_id"] is None:
|
||||||
data_json["user_id"] = str(uuid.uuid4())
|
data_json["user_id"] = str(uuid.uuid4())
|
||||||
|
@ -169,6 +210,7 @@ async def new_user(
|
||||||
try:
|
try:
|
||||||
from litellm.proxy.proxy_server import (
|
from litellm.proxy.proxy_server import (
|
||||||
general_settings,
|
general_settings,
|
||||||
|
litellm_proxy_admin_name,
|
||||||
prisma_client,
|
prisma_client,
|
||||||
proxy_logging_obj,
|
proxy_logging_obj,
|
||||||
)
|
)
|
||||||
|
@ -254,6 +296,34 @@ async def new_user(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
if prisma_client is None:
|
||||||
|
raise Exception(CommonProxyErrors.db_not_connected_error.value)
|
||||||
|
user_row: BaseModel = await prisma_client.db.litellm_usertable.find_first(
|
||||||
|
where={"user_id": response["user_id"]}
|
||||||
|
)
|
||||||
|
|
||||||
|
user_row_litellm_typed = LiteLLM_UserTable(
|
||||||
|
**user_row.model_dump(exclude_none=True)
|
||||||
|
)
|
||||||
|
asyncio.create_task(
|
||||||
|
create_internal_user_audit_log(
|
||||||
|
user_id=user_row_litellm_typed.user_id,
|
||||||
|
action="created",
|
||||||
|
litellm_changed_by=user_api_key_dict.user_id,
|
||||||
|
user_api_key_dict=user_api_key_dict,
|
||||||
|
litellm_proxy_admin_name=litellm_proxy_admin_name,
|
||||||
|
before_value=None,
|
||||||
|
after_value=user_row_litellm_typed.model_dump_json(
|
||||||
|
exclude_none=True
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
verbose_proxy_logger.warning(
|
||||||
|
"Unable to create audit log for user on `/user/new` - {}".format(str(e))
|
||||||
|
)
|
||||||
|
|
||||||
return NewUserResponse(
|
return NewUserResponse(
|
||||||
key=response.get("token", ""),
|
key=response.get("token", ""),
|
||||||
expires=response.get("expires", None),
|
expires=response.get("expires", None),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue