mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-06 08:16:43 +00:00
Merge pull request #5166 from BerriAI/litellm_log_key_created_slack
[Feat-Security] Send Slack Alert when CRUD ops done on Virtual Keys, Teams, Internal Users
This commit is contained in:
commit
c401970522
4 changed files with 119 additions and 1 deletions
|
|
@ -26,7 +26,13 @@ from litellm.caching import DualCache
|
|||
from litellm.integrations.custom_logger import CustomLogger
|
||||
from litellm.litellm_core_utils.litellm_logging import Logging
|
||||
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler
|
||||
from litellm.proxy._types import AlertType, CallInfo, UserAPIKeyAuth, WebhookEvent
|
||||
from litellm.proxy._types import (
|
||||
AlertType,
|
||||
CallInfo,
|
||||
UserAPIKeyAuth,
|
||||
VirtualKeyEvent,
|
||||
WebhookEvent,
|
||||
)
|
||||
from litellm.types.router import LiteLLM_Params
|
||||
|
||||
from .email_templates.templates import *
|
||||
|
|
@ -1788,3 +1794,46 @@ Model Info:
|
|||
verbose_proxy_logger.error("Error sending weekly spend report %s", e)
|
||||
|
||||
pass
|
||||
|
||||
async def send_virtual_key_event_slack(
|
||||
self,
|
||||
key_event: VirtualKeyEvent,
|
||||
event_name: str,
|
||||
):
|
||||
"""
|
||||
Helper to send fallback statistics from prometheus server -> to slack
|
||||
|
||||
This runs once per day and sends an overview of all the fallback statistics
|
||||
"""
|
||||
try:
|
||||
message = f"`{event_name}`\n"
|
||||
|
||||
key_event_dict = key_event.model_dump()
|
||||
|
||||
# Add Created by information first
|
||||
message += "*Action Done by:*\n"
|
||||
for key, value in key_event_dict.items():
|
||||
if "created_by" in key:
|
||||
message += f"{key}: `{value}`\n"
|
||||
|
||||
# Add args sent to function in the alert
|
||||
message += "\n*Arguments passed:*\n"
|
||||
request_kwargs = key_event.request_kwargs
|
||||
for key, value in request_kwargs.items():
|
||||
if key == "user_api_key_dict":
|
||||
continue
|
||||
message += f"{key}: `{value}`\n"
|
||||
|
||||
await self.send_alert(
|
||||
message=message,
|
||||
level="High",
|
||||
alert_type="fallback_reports",
|
||||
alerting_metadata={},
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.error(
|
||||
"Error sending send_virtual_key_event_slack %s", e
|
||||
)
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1754,3 +1754,10 @@ class SSOUserDefinedValues(TypedDict):
|
|||
user_role: Optional[str]
|
||||
max_budget: Optional[float]
|
||||
budget_duration: Optional[str]
|
||||
|
||||
|
||||
class VirtualKeyEvent(LiteLLMBase):
|
||||
created_by_user_id: str
|
||||
created_by_user_role: str
|
||||
created_by_key_alias: Optional[str]
|
||||
request_kwargs: dict
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import litellm
|
|||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.proxy._types import *
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
from litellm.proxy.management_helpers.utils import management_endpoint_wrapper
|
||||
from litellm.proxy.utils import _duration_in_seconds
|
||||
|
||||
router = APIRouter()
|
||||
|
|
@ -37,6 +38,7 @@ router = APIRouter()
|
|||
dependencies=[Depends(user_api_key_auth)],
|
||||
response_model=GenerateKeyResponse,
|
||||
)
|
||||
@management_endpoint_wrapper
|
||||
async def generate_key_fn(
|
||||
data: GenerateKeyRequest,
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
|
|
@ -278,6 +280,7 @@ async def generate_key_fn(
|
|||
@router.post(
|
||||
"/key/update", tags=["key management"], dependencies=[Depends(user_api_key_auth)]
|
||||
)
|
||||
@management_endpoint_wrapper
|
||||
async def update_key_fn(
|
||||
request: Request,
|
||||
data: UpdateKeyRequest,
|
||||
|
|
@ -398,6 +401,7 @@ async def update_key_fn(
|
|||
@router.post(
|
||||
"/key/delete", tags=["key management"], dependencies=[Depends(user_api_key_auth)]
|
||||
)
|
||||
@management_endpoint_wrapper
|
||||
async def delete_key_fn(
|
||||
data: KeyRequest,
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from litellm.proxy._types import ( # key request types; user request types; tea
|
|||
UpdateTeamRequest,
|
||||
UpdateUserRequest,
|
||||
UserAPIKeyAuth,
|
||||
VirtualKeyEvent,
|
||||
)
|
||||
from litellm.proxy.common_utils.http_parsing_utils import _read_request_body
|
||||
from litellm.proxy.utils import PrismaClient
|
||||
|
|
@ -186,6 +187,56 @@ def _delete_customer_id_from_cache(kwargs):
|
|||
pass
|
||||
|
||||
|
||||
async def send_management_endpoint_alert(
|
||||
request_kwargs: dict,
|
||||
user_api_key_dict: UserAPIKeyAuth,
|
||||
function_name: str,
|
||||
):
|
||||
"""
|
||||
Sends a slack alert when:
|
||||
- A virtual key is created, updated, or deleted
|
||||
- An internal user is created, updated, or deleted
|
||||
- A team is created, updated, or deleted
|
||||
"""
|
||||
from litellm.proxy.proxy_server import premium_user, proxy_logging_obj
|
||||
|
||||
if premium_user is not True:
|
||||
return
|
||||
|
||||
management_function_to_event_name = {
|
||||
"generate_key_fn": "New Virtual Key Created",
|
||||
"update_key_fn": "Virtual Key Updated",
|
||||
"delete_key_fn": "Virtual Key Deleted",
|
||||
# Team events
|
||||
"new_team": "New Team Created",
|
||||
"update_team": "Team Updated",
|
||||
"delete_team": "Team Deleted",
|
||||
# Internal User events
|
||||
"new_user": "New Internal User Created",
|
||||
"user_update": "Internal User Updated",
|
||||
"delete_user": "Internal User Deleted",
|
||||
}
|
||||
|
||||
if (
|
||||
proxy_logging_obj is not None
|
||||
and proxy_logging_obj.slack_alerting_instance is not None
|
||||
):
|
||||
|
||||
# Virtual Key Events
|
||||
if function_name in management_function_to_event_name:
|
||||
key_event = VirtualKeyEvent(
|
||||
created_by_user_id=user_api_key_dict.user_id or "Unknown",
|
||||
created_by_user_role=user_api_key_dict.user_role or "Unknown",
|
||||
created_by_key_alias=user_api_key_dict.key_alias,
|
||||
request_kwargs=request_kwargs,
|
||||
)
|
||||
|
||||
event_name = management_function_to_event_name[function_name]
|
||||
await proxy_logging_obj.slack_alerting_instance.send_virtual_key_event_slack(
|
||||
key_event=key_event, event_name=event_name
|
||||
)
|
||||
|
||||
|
||||
def management_endpoint_wrapper(func):
|
||||
"""
|
||||
This wrapper does the following:
|
||||
|
|
@ -207,6 +258,13 @@ def management_endpoint_wrapper(func):
|
|||
user_api_key_dict: UserAPIKeyAuth = (
|
||||
kwargs.get("user_api_key_dict") or UserAPIKeyAuth()
|
||||
)
|
||||
|
||||
await send_management_endpoint_alert(
|
||||
request_kwargs=kwargs,
|
||||
user_api_key_dict=user_api_key_dict,
|
||||
function_name=func.__name__,
|
||||
)
|
||||
|
||||
_http_request: Request = kwargs.get("http_request")
|
||||
parent_otel_span = user_api_key_dict.parent_otel_span
|
||||
if parent_otel_span is not None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue