Skip to content

Commit 54f0af2

Browse files
authored
User security context to model args instead of user json (#1318)
1 parent bc93393 commit 54f0af2

4 files changed

Lines changed: 38 additions & 19 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ Note: RBAC assignments can take a few minutes before becoming effective.
151151
|AZURE_OPENAI_SYSTEM_MESSAGE|No|You are an AI assistant that helps people find information.|A brief description of the role and tone the model should use|
152152
|AZURE_OPENAI_STREAM|No|True|Whether or not to use streaming for the response. Note: Setting this to true prevents the use of prompt flow.|
153153
|AZURE_OPENAI_EMBEDDING_NAME|Only if using vector search using an Azure OpenAI embedding model||The name of your embedding model deployment if using vector search.
154+
|MS_DEFENDER_ENABLED|Yes|True|Whether or not the Microsoft Defender for Cloud's threat protection for AI workloads plan is enabled on your subscription or not , for more details [Microsoft Defender for Cloud documentation](https://learn.microsoft.com/azure/defender-for-cloud/gain-end-user-context-ai).|
154155

155156
See the [documentation](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/reference#example-response-2) for more information on these parameters.
156157

README_azd.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ Run the following commands based on what you want to customize:
5050
* `azd env set AZURE_FORMRECOGNIZER_SERVICE_RESOURCE_GROUP {Name of existing resource group that Form Recognizer service is provisioned to}`.
5151
* `azd env set AZURE_FORMRECOGNIZER_SKU_NAME {Name of Form Recognizer SKU}`. Defaults to 'S0'.
5252

53+
If you have enabled Microsoft Defender for Cloud's threat protection for AI workloads on your Azure OpenAI resource and want to add user context to alerts, you can do so by using the azd commands below. If you haven't set up threat protection yet, please follow this guide: [Microsoft Defender for Cloud documentation](https://learn.microsoft.com/azure/defender-for-cloud/gain-end-user-context-ai).
54+
55+
To add security context to your alerts, run the following command:
56+
57+
```bash
58+
azd env set MS_DEFENDER_ENABLED true
59+
```
60+
61+
5362
1. Run `azd auth login` to login to your Azure account.
5463
1. Run `azd up` to provision Azure resources and deploy this sample to those resources. This also runs a script to build the search index based on files in the `./data` folder.
5564
1. After the application has been successfully deployed you will see a URL printed to the console. Click that URL to interact with the application in your browser.

app.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,12 @@ def prepare_model_args(request_body, request_headers):
274274
messages.append(messages_helper)
275275

276276

277-
user_json = None
277+
user_security_context = None
278278
if (MS_DEFENDER_ENABLED):
279279
authenticated_user_details = get_authenticated_user_details(request_headers)
280-
conversation_id = request_body.get("conversation_id", None)
281280
application_name = app_settings.ui.title
282-
user_json = get_msdefender_user_json(authenticated_user_details, request_headers, conversation_id, application_name)
281+
user_security_context = get_msdefender_user_json(authenticated_user_details, request_headers, application_name ) # security component introduced here https://learn.microsoft.com/en-us/azure/defender-for-cloud/gain-end-user-context-ai
282+
283283

284284
model_args = {
285285
"messages": messages,
@@ -288,8 +288,7 @@ def prepare_model_args(request_body, request_headers):
288288
"top_p": app_settings.azure_openai.top_p,
289289
"stop": app_settings.azure_openai.stop_sequence,
290290
"stream": app_settings.azure_openai.stream,
291-
"model": app_settings.azure_openai.model,
292-
"user": user_json
291+
"model": app_settings.azure_openai.model
293292
}
294293

295294
if len(messages) > 0:
@@ -340,6 +339,10 @@ def prepare_model_args(request_body, request_headers):
340339
"embedding_dependency"
341340
]["authentication"][field] = "*****"
342341

342+
if model_args.get("extra_body") is None:
343+
model_args["extra_body"] = {}
344+
if user_security_context: # security component introduced here https://learn.microsoft.com/en-us/azure/defender-for-cloud/gain-end-user-context-ai
345+
model_args["extra_body"]["user_security_context"]= user_security_context.to_dict()
343346
logging.debug(f"REQUEST BODY: {json.dumps(model_args_clean, indent=4)}")
344347

345348
return model_args
@@ -1057,4 +1060,4 @@ async def generate_title(conversation_messages) -> str:
10571060
return messages[-2]["content"]
10581061

10591062

1060-
app = create_app()
1063+
app = create_app()
Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import json
1+
from typing import Dict, Any
2+
from dataclasses import dataclass, asdict, field
3+
import os
24

3-
def get_msdefender_user_json(authenticated_user_details, request_headers, conversation_id, application_name):
4-
auth_provider = authenticated_user_details.get('auth_provider')
5+
6+
@dataclass
7+
class UserSecurityContext:
8+
application_name: str = field(default=None)
9+
end_user_id: str = field(default=None)
10+
end_user_tenant_id: str = field(default=None)
11+
source_ip: str = field(default=None)
12+
def to_dict(self) -> Dict[str, Any]:
13+
return {k: v for k, v in asdict(self).items() if v is not None}
14+
15+
16+
def get_msdefender_user_json(authenticated_user_details, request_headers, application_name) -> UserSecurityContext:
517
source_ip = request_headers.get('Remote-Addr', '')
6-
header_names = ['User-Agent', 'X-Forwarded-For', 'Forwarded', 'X-Real-IP', 'True-Client-IP', 'CF-Connecting-IP']
7-
user_args = {
8-
"EndUserId": authenticated_user_details.get('user_principal_id'),
9-
"EndUserIdType": "EntraId" if auth_provider == "aad" else auth_provider,
10-
"SourceIp": source_ip.split(':')[0], #remove port
11-
"SourceRequestHeaders": {header: request_headers[header] for header in header_names if header in request_headers},
12-
"ConversationId": conversation_id,
13-
"ApplicationName": application_name,
14-
}
15-
return json.dumps(user_args)
18+
end_user_id = authenticated_user_details.get('user_principal_id')
19+
source_ip= source_ip.split(':')[0]
20+
return UserSecurityContext(end_user_id=end_user_id, source_ip=source_ip, application_name=application_name, end_user_tenant_id=None)
21+

0 commit comments

Comments
 (0)