Cloud-AI-forensics: Azure
Forensische onderzoekstechnieken voor Azure AI-diensten waaronder Azure OpenAI, Azure ML en Cognitive Services, met diagnostische logging en bewijsverzameling.
Overzicht
Microsoft Azure host AI-workloads via Azure OpenAI Service (beheerde GPT- en DALL-E-modellen), Azure Machine Learning (training en uitrol van custom modellen) en Cognitive Services (kant-en-klare AI-modellen voor vision, speech, language en decision). De AI-diensten van Azure zijn nauw geïntegreerd met het bredere Azure-ecosysteem: Entra ID voor authenticatie, Azure Monitor voor observability, Key Vault voor secretsbeheer en Log Analytics voor gecentraliseerde loganalyse.
Deze integratie is een forensisch voordeel. Anders dan bij standalone AI-uitrollen, waar logging voor elke component expliciet geconfigureerd moet worden, biedt de diagnostische logging-infrastructuur van Azure een uniform framework voor het vastleggen van AI-dienstactiviteit. Mits correct geconfigureerd kan Azure elke Azure OpenAI API-call loggen met volledige prompt- en response-inhoud, elke Azure ML-experiment- en uitrolactie, en elk Cognitive Services-verzoek met invoer-/uitvoerdata.
De forensische uitdaging op Azure is dat deze logging voor de meeste AI-diensten niet standaard is ingeschakeld. Organisaties die geen diagnostische instellingen hebben geconfigureerd vóór een incident, zullen merken dat cruciaal bewijs ontbreekt. Daarnaast betekent het op rollen gebaseerde toegangsbeheer (RBAC) van Azure dat de onderzoeker zowel het data plane (wie de AI-API aanriep) als het control plane (wie de AI-dienst configureerde) moet begrijpen om een compleet beeld op te bouwen.
Dit artikel behandelt het verzamelen van forensische artefacten over de AI-diensten van Azure heen, analysetechnieken voor veelvoorkomende incidentscenario's, en het configureren van forensische paraatheid om ervoor te zorgen dat bewijs beschikbaar is wanneer dat nodig is.
Bronnen van forensische artefacten in Azure AI
Azure Activity Log en Diagnostic Logs
De logging-architectuur van Azure kent twee primaire lagen. De Activity Log legt control plane-operaties vast (het aanmaken, wijzigen of verwijderen van resources). Diagnostic Logs leggen data plane-operaties vast (de daadwerkelijke API-calls naar de AI-diensten). Beide zijn essentieel voor AI-forensics.
from azure.identity import DefaultAzureCredential
from azure.mgmt.monitor import MonitorManagementClient
from azure.monitor.query import LogsQueryClient, LogsQueryStatus
from datetime import datetime, timedelta, timezone
from dataclasses import dataclass, field
from typing import Optional
import json
@dataclass
class AzureAIForensicEvent:
"""Een geparseerde forensische gebeurtenis uit Azure AI."""
timestamp: str
operation_name: str
resource_type: str
resource_name: str
caller_identity: str
caller_ip: str
status: str
properties: dict
correlation_id: str = ""
category: str = ""
class AzureAIForensicCollector:
"""Verzamel en analyseer forensische artefacten uit Azure AI-diensten."""
def __init__(
self,
subscription_id: str,
resource_group: str,
credential: Optional[DefaultAzureCredential] = None,
):
self.subscription_id = subscription_id
self.resource_group = resource_group
self.credential = credential or DefaultAzureCredential()
self.monitor_client = MonitorManagementClient(
self.credential, subscription_id
)
self.logs_client = LogsQueryClient(self.credential)
def collect_activity_log_events(
self,
start_time: datetime,
end_time: datetime,
resource_types: Optional[list[str]] = None,
) -> list[AzureAIForensicEvent]:
"""
Verzamel Azure Activity Log-gebeurtenissen voor AI-resources.
Args:
start_time: Begin van het onderzoeksvenster.
end_time: Einde van het onderzoeksvenster.
resource_types: Azure-resourcetypes om op te filteren.
Standaard veelvoorkomende AI-resourcetypes.
Returns:
Lijst met geparseerde forensische gebeurtenissen.
"""
if resource_types is None:
resource_types = [
"Microsoft.CognitiveServices/accounts",
"Microsoft.MachineLearningServices/workspaces",
]
# Bouw een OData-filter voor de Activity Log-query
time_filter = (
f"eventTimestamp ge '{start_time.isoformat()}' "
f"and eventTimestamp le '{end_time.isoformat()}'"
)
rg_filter = f"resourceGroupName eq '{self.resource_group}'"
odata_filter = f"{time_filter} and {rg_filter}"
events = []
try:
activity_logs = self.monitor_client.activity_logs.list(
filter=odata_filter
)
for log in activity_logs:
# Filter op resourcetype
resource_type = getattr(log, "resource_type", {})
rt_value = getattr(resource_type, "value", "") if resource_type else ""
if resource_types and rt_value not in resource_types:
continue
caller = getattr(log, "caller", "unknown")
claims = getattr(log, "claims", {}) or {}
ip_address = claims.get(
"ipaddr",
claims.get("http://schemas.microsoft.com/claims/authnclassreference", "unknown"),
)
status_obj = getattr(log, "status", None)
status_value = getattr(status_obj, "value", "unknown") if status_obj else "unknown"
events.append(AzureAIForensicEvent(
timestamp=str(getattr(log, "event_timestamp", "")),
operation_name=getattr(
getattr(log, "operation_name", None), "value", "unknown"
),
resource_type=rt_value,
resource_name=getattr(log, "resource_id", "unknown"),
caller_identity=caller,
caller_ip=str(ip_address),
status=status_value,
properties=dict(getattr(log, "properties", {}) or {}),
correlation_id=str(getattr(log, "correlation_id", "")),
category=str(getattr(
getattr(log, "category", None), "value", ""
)),
))
except Exception as e:
print(f"Error collecting activity logs: {e}")
return events
def query_log_analytics(
self,
workspace_id: str,
query: str,
timespan: Optional[timedelta] = None,
) -> list[dict]:
"""
Voer een KQL-query uit tegen een Log Analytics-workspace.
Args:
workspace_id: De Log Analytics-workspace-ID.
query: KQL-querystring.
timespan: Tijdsbereik voor de query.
Returns:
Lijst met resultaatrijen als dicts.
"""
if timespan is None:
timespan = timedelta(days=7)
try:
response = self.logs_client.query_workspace(
workspace_id=workspace_id,
query=query,
timespan=timespan,
)
if response.status == LogsQueryStatus.SUCCESS:
results = []
for table in response.tables:
columns = [col.name for col in table.columns]
for row in table.rows:
results.append(dict(zip(columns, row)))
return results
else:
return [{"error": f"Query failed: {response.status}"}]
except Exception as e:
return [{"error": str(e)}]Forensics van Azure OpenAI Service
Azure OpenAI Service is de meest onderzochte Azure AI-dienst, omdat deze natuurlijke-taalprompts verwerkt die gevoelige data kunnen bevatten en omdat de outputs geslaagde aanvallen kunnen onthullen. Wanneer diagnostische logging is ingeschakeld, logt Azure OpenAI de volledige request- en response-inhoud naar Log Analytics.
class AzureOpenAIForensicAnalyzer:
"""Forensische analyse specifiek voor Azure OpenAI Service."""
def __init__(self, collector: AzureAIForensicCollector):
self.collector = collector
def investigate_api_usage(
self,
workspace_id: str,
resource_name: str,
start_time: datetime,
end_time: datetime,
) -> dict:
"""
Onderzoek de gebruikspatronen van de Azure OpenAI-API.
Args:
workspace_id: Log Analytics-workspace-ID.
resource_name: Naam van de Azure OpenAI-resource.
start_time: Begin van het onderzoeksvenster.
end_time: Einde van het onderzoeksvenster.
Returns:
Dict met onderzoeksresultaten.
"""
results = {
"resource": resource_name,
"period": {
"start": start_time.isoformat(),
"end": end_time.isoformat(),
},
"usage_summary": {},
"suspicious_requests": [],
"content_policy_violations": [],
"error_analysis": {},
}
# Bevraag gebruiksoverzicht per model en caller
usage_query = f"""
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Resource =~ "{resource_name}"
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where OperationName == "ChatCompletions_Create"
or OperationName == "Completions_Create"
or OperationName == "Embeddings_Create"
| summarize
RequestCount = count(),
TotalTokens = sum(toint(properties_s)),
AvgDurationMs = avg(DurationMs)
by OperationName, CallerIPAddress, identity_claim_appid_s
| order by RequestCount desc
"""
timespan = end_time - start_time
usage_data = self.collector.query_log_analytics(
workspace_id, usage_query, timespan
)
results["usage_summary"] = usage_data
# Bevraag schendingen van het contentbeleid (HTTP 400 met
# content_filter-redenen)
violation_query = f"""
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Resource =~ "{resource_name}"
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where ResultSignature == "400"
| where properties_s contains "content_filter"
| project
TimeGenerated,
OperationName,
CallerIPAddress,
ResultSignature,
properties_s,
identity_claim_appid_s
| order by TimeGenerated asc
"""
violations = self.collector.query_log_analytics(
workspace_id, violation_query, timespan
)
results["content_policy_violations"] = violations
# Bevraag verzoekpatronen die wijzen op prompt-injectie
# of jailbreak-pogingen (hoge foutpercentages gevolgd door successen)
pattern_query = f"""
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Resource =~ "{resource_name}"
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| summarize
TotalRequests = count(),
FailedRequests = countif(ResultSignature != "200"),
SuccessAfterFailure = countif(
ResultSignature == "200"
and prev(ResultSignature) != "200"
)
by bin(TimeGenerated, 5m), CallerIPAddress
| where FailedRequests > 5
| order by TimeGenerated asc
"""
pattern_data = self.collector.query_log_analytics(
workspace_id, pattern_query, timespan
)
results["suspicious_requests"] = pattern_data
return results
def collect_prompt_response_logs(
self,
workspace_id: str,
resource_name: str,
start_time: datetime,
end_time: datetime,
caller_ip: Optional[str] = None,
max_results: int = 1000,
) -> list[dict]:
"""
Verzamel volledige prompt- en response-logs uit Azure OpenAI.
Vereist dat diagnostische logging met request-/response-
body-logging is ingeschakeld.
Args:
workspace_id: Log Analytics-workspace-ID.
resource_name: Naam van de Azure OpenAI-resource.
start_time: Begin van het verzamelvenster.
end_time: Einde van het verzamelvenster.
caller_ip: Optioneel filter voor een specifiek caller-IP.
max_results: Maximaal aantal resultaten.
Returns:
Lijst met prompt-/response-logregels.
"""
ip_filter = ""
if caller_ip:
ip_filter = f'| where CallerIPAddress == "{caller_ip}"'
query = f"""
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.COGNITIVESERVICES"
| where Resource =~ "{resource_name}"
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where OperationName == "ChatCompletions_Create"
{ip_filter}
| project
TimeGenerated,
OperationName,
CallerIPAddress,
DurationMs,
ResultSignature,
properties_s,
identity_claim_appid_s
| order by TimeGenerated asc
| take {max_results}
"""
timespan = end_time - start_time
return self.collector.query_log_analytics(
workspace_id, query, timespan
)Forensics van Azure Machine Learning
Azure ML-workspaces genereren forensische artefacten via experimenten, modelregistraties, endpoint-uitrollen en compute-operaties. De Activity Log van de workspace legt control plane-acties vast, terwijl de diagnostische logs van de workspace data plane-operaties vastleggen.
class AzureMLForensicAnalyzer:
"""Forensische analyse specifiek voor Azure Machine Learning."""
def __init__(self, collector: AzureAIForensicCollector):
self.collector = collector
def investigate_workspace_activity(
self,
workspace_id: str,
log_analytics_workspace_id: str,
start_time: datetime,
end_time: datetime,
) -> dict:
"""
Onderzoek activiteit in een Azure ML-workspace.
Args:
workspace_id: De resource-ID van de Azure ML-workspace.
log_analytics_workspace_id: Log Analytics-workspace-ID.
start_time: Begin van het onderzoeksvenster.
end_time: Einde van het onderzoeksvenster.
Returns:
Dict met onderzoeksresultaten.
"""
results = {
"workspace_id": workspace_id,
"model_registry_changes": [],
"endpoint_modifications": [],
"compute_activity": [],
"data_access_events": [],
}
timespan = end_time - start_time
# Controleer het modelregister op wijzigingen
model_query = f"""
AmlComputeClusterEvent
| union AmlRunStatusChangedEvent
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| project TimeGenerated, OperationName, Identity, Properties=properties_s
| order by TimeGenerated asc
"""
results["compute_activity"] = self.collector.query_log_analytics(
log_analytics_workspace_id, model_query, timespan
)
# Controleer op modelregistratie- en uitrolgebeurtenissen
deployment_query = f"""
AzureActivity
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where ResourceProvider == "MICROSOFT.MACHINELEARNINGSERVICES"
| where OperationNameValue contains "model"
or OperationNameValue contains "endpoint"
or OperationNameValue contains "deployment"
| project
TimeGenerated,
OperationNameValue,
Caller,
CallerIpAddress,
ActivityStatusValue,
Properties
| order by TimeGenerated asc
"""
deployment_data = self.collector.query_log_analytics(
log_analytics_workspace_id, deployment_query, timespan
)
results["endpoint_modifications"] = deployment_data
return results
def check_model_registry_integrity(
self,
workspace_id: str,
log_analytics_workspace_id: str,
model_name: str,
start_time: datetime,
end_time: datetime,
) -> dict:
"""
Controleer de integriteit van een model in het Azure ML-register
door de versiegeschiedenis en toegangspatronen te onderzoeken.
Args:
workspace_id: Resource-ID van de Azure ML-workspace.
log_analytics_workspace_id: Log Analytics-workspace-ID.
model_name: Naam van het te onderzoeken model.
start_time: Begin van het onderzoeksvenster.
end_time: Einde van het onderzoeksvenster.
Returns:
Dict met beoordeling van de modelintegriteit.
"""
timespan = end_time - start_time
query = f"""
AzureActivity
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where ResourceProvider == "MICROSOFT.MACHINELEARNINGSERVICES"
| where Properties contains "{model_name}"
| project
TimeGenerated,
OperationNameValue,
Caller,
CallerIpAddress,
ActivityStatusValue,
Properties
| order by TimeGenerated asc
"""
events = self.collector.query_log_analytics(
log_analytics_workspace_id, query, timespan
)
findings = []
for event in events:
op_name = event.get("OperationNameValue", "")
if "write" in op_name.lower() or "delete" in op_name.lower():
findings.append({
"type": "model_modification",
"severity": "high",
"operation": op_name,
"timestamp": str(event.get("TimeGenerated")),
"caller": event.get("Caller"),
"ip": event.get("CallerIpAddress"),
})
return {
"model_name": model_name,
"events_found": len(events),
"modification_events": len(findings),
"findings": findings,
}Entra ID-integratie voor identiteitsforensics
Azure AI-diensten authenticeren via Entra ID (voorheen Azure Active Directory), dat een rijk auditspoor van authenticatiegebeurtenissen biedt. Voor forensische onderzoeken onthullen de Entra ID-aanmeldlogs wie zich authenticeerde, vanaf welk apparaat en welke locatie, op welk tijdstip, en of er conditional access-beleidsregels werden toegepast of omzeild.
Correleer bij het onderzoeken van ongeautoriseerde toegang tot Azure AI-diensten de diagnostische logs van de AI-dienst met de Entra ID-aanmeldlogs. De applicatie-ID (appId-claim) in de logs van de AI-dienst komt overeen met de applicatieregistratie in Entra ID. Bevraag de aanmeldlogs voor die applicatie om alle authenticatiegebeurtenissen te identificeren, inclusief mislukte pogingen die kunnen wijzen op credential stuffing of brute force-aanvallen.
Entra ID legt ook aanmeldlogs van service principals vast, die cruciaal zijn voor het onderzoeken van gecompromitteerde service-accounts. Veel Azure AI-uitrollen gebruiken service principals voor geautomatiseerde toegang. Als de credentials van een service principal worden gecompromitteerd, krijgt de aanvaller dezelfde toegang als het geautomatiseerde systeem. Aanmeldlogs van service principals tonen de IP-adressen en tijdstempels van alle authenticatiegebeurtenissen voor de principal.
def query_entra_signin_logs(
collector: AzureAIForensicCollector,
workspace_id: str,
app_id: str,
start_time: datetime,
end_time: datetime,
) -> list[dict]:
"""
Bevraag de Entra ID-aanmeldlogs voor een specifieke applicatie.
Args:
collector: De forensische collector-instantie.
workspace_id: Log Analytics-workspace-ID.
app_id: De applicatie- (client-)ID die onderzocht moet worden.
start_time: Begin van het onderzoeksvenster.
end_time: Einde van het onderzoeksvenster.
Returns:
Lijst met aanmeldgebeurtenissen.
"""
timespan = end_time - start_time
query = f"""
SigninLogs
| where TimeGenerated between (
datetime({start_time.strftime('%Y-%m-%dT%H:%M:%S')})
.. datetime({end_time.strftime('%Y-%m-%dT%H:%M:%S')})
)
| where AppId == "{app_id}"
| project
TimeGenerated,
UserPrincipalName,
AppDisplayName,
IPAddress,
Location,
ResultType,
ResultDescription,
ClientAppUsed,
ConditionalAccessStatus,
RiskLevelDuringSignIn,
DeviceDetail
| order by TimeGenerated asc
"""
return collector.query_log_analytics(workspace_id, query, timespan)Forensics op netwerkniveau voor Azure AI
Azure Network Watcher en NSG Flow Logs bieden zichtbaarheid op netwerkniveau in het verkeer van AI-diensten. Voor Azure ML-compute-instances en endpoints die binnen een VNet zijn uitgerold, leggen NSG Flow Logs alle inkomende en uitgaande netwerkverbindingen vast. Deze data is waardevol voor het detecteren van data-exfiltratie (grote uitgaande overdrachten naar onverwachte bestemmingen), pogingen tot ongeautoriseerde toegang (inkomende verbindingen vanaf onverwachte bronnen) en laterale beweging (verbindingen tussen AI-resources en andere interne systemen die niet zouden moeten communiceren).
Schakel NSG Flow Logs versie 2 in, die naast de basis-vijftuple (bron-IP, bestemmings-IP, bronpoort, bestemmingspoort, protocol) ook byte-tellingen en flow-state-informatie bevat. Stuur flow logs naar een Storage Account en een Log Analytics-workspace voor analyse. Configureer voor realtime detectie Traffic Analytics, dat geaggregeerde flow-analyse en anomaliedetectie biedt.
Onderzoek naar veelvoorkomende Azure AI-incidentscenario's
Key Vault-forensics voor AI-API-sleutels
Veel Azure AI-uitrollen slaan API-sleutels en connection strings op in Azure Key Vault. Bij het onderzoeken van mogelijke credential-compromittering zijn de auditlogs van Key Vault essentieel. De diagnostische logs van Key Vault registreren elke lees-, schrijf- en verwijderoperatie op een secret, samen met de caller-identiteit en het IP-adres.
Bevraag de Key Vault-logs om te bepalen: wanneer AI-dienstsleutels voor het laatst werden benaderd, welke identiteiten ze benaderden, of er secrets onverwacht zijn aangemaakt of gewijzigd, en of er secret-backup- of -restore-operaties zijn uitgevoerd (wat erop kan wijzen dat een aanvaller sleutels exporteert voor gebruik buiten de omgeving).
Schakel de purge protection- en soft delete-functies van Key Vault in om permanente verwijdering van secrets tijdens een incident te voorkomen. Een aanvaller die toegang tot Key Vault krijgt, zou kunnen proberen secrets te verwijderen om zijn sporen uit te wissen. Met soft delete ingeschakeld blijven verwijderde secrets herstelbaar gedurende de geconfigureerde bewaarperiode.
Scenario 1: Omzeilen van het Azure OpenAI-contentbeleid
Een aanvaller ontdekt een manier om de contentfiltering van Azure OpenAI te omzeilen om verboden inhoud te genereren. Onderzoeksstappen:
- Bevraag de diagnostische logs op schendingen van het contentfilter (HTTP 400-responses met content_filter-foutcodes) om de aanvalspogingen te zien.
- Identificeer geslaagde verzoeken van hetzelfde caller-IP of dezelfde applicatie-ID die op de mislukte pogingen volgen, aangezien deze geslaagde bypasses kunnen vertegenwoordigen.
- Verzamel de volledige prompt-/response-inhoud van geslaagde verzoeken om te bepalen wat er is gegenereerd.
- Correleer de applicatie-ID met Entra ID om de applicatie en de eigenaren ervan te identificeren.
- Controleer of de contentfiltering-configuratie is gewijzigd: bevraag de Activity Log op Write-operaties op de contentbeleidsinstellingen van de Azure OpenAI-resource.
Scenario 2: Ongeautoriseerde uitrol van een Azure ML-model
Een aanvaller rolt een kwaadaardig model uit naar een Azure ML-endpoint en vervangt daarmee het legitieme model. Onderzoeksstappen:
- Bevraag de Azure Activity Log op Write-operaties op endpoints (modeluitrol, wijzigingen in endpointconfiguratie).
- Identificeer de caller-identiteit en verifieer of de uitrol via je change management-proces was geautoriseerd.
- Controleer de versiegeschiedenis van het modelregister om te bepalen of er een nieuwe modelversie is geregistreerd of een bestaande versie is gewijzigd.
- Vergelijk de hash van het uitgerolde model met de verwachte hash uit je CI/CD-pijplijn.
- Verzamel Azure ML-compute-logs om te controleren op ongeautoriseerde trainingsjobs die het kwaadaardige model kunnen hebben geproduceerd.
Scenario 3: Data-exfiltratie via Cognitive Services
Een insider gebruikt Cognitive Services om gevoelige documenten te verwerken en te exfiltreren (bijv. door Document Intelligence te gebruiken om vertrouwelijke documenten te OCR'en en de tekst naar een extern endpoint te sturen). Onderzoek dit door diagnostische logs voor de Cognitive Services-resource te verzamelen, de caller en het volume aan verwerkte documenten te identificeren, en kruisverwijzingen te maken met netwerklogs om te bepalen waar de verwerkte output naartoe werd gestuurd.
Configuratie van forensische paraatheid voor Azure AI
Essentiële diagnostische instellingen
Configureer de volgende diagnostische instellingen voordat een incident plaatsvindt:
def configure_azure_ai_forensic_logging(
subscription_id: str,
resource_group: str,
resource_name: str,
resource_type: str,
log_analytics_workspace_id: str,
storage_account_id: str,
) -> dict:
"""
Configureer diagnostische instellingen voor een Azure AI-resource
om forensische paraatheid te garanderen.
Args:
subscription_id: Azure-abonnements-ID.
resource_group: Naam van de resourcegroep.
resource_name: Naam van de AI-resource.
resource_type: Resourcetype (bijv. "Microsoft.CognitiveServices/accounts").
log_analytics_workspace_id: Resource-ID van de Log Analytics-workspace.
storage_account_id: Storage-account voor langetermijnbewaring van logs.
Returns:
Dict met configuratieresultaat.
"""
credential = DefaultAzureCredential()
monitor = MonitorManagementClient(credential, subscription_id)
resource_id = (
f"/subscriptions/{subscription_id}"
f"/resourceGroups/{resource_group}"
f"/providers/{resource_type}/{resource_name}"
)
# Definieer een diagnostische instelling met alle relevante logcategorieën
diagnostic_settings = {
"storage_account_id": storage_account_id,
"workspace_id": log_analytics_workspace_id,
"logs": [
{
"category": "Audit",
"enabled": True,
"retention_policy": {
"enabled": True,
"days": 365,
},
},
{
"category": "RequestResponse",
"enabled": True,
"retention_policy": {
"enabled": True,
"days": 90,
},
},
{
"category": "Trace",
"enabled": True,
"retention_policy": {
"enabled": True,
"days": 90,
},
},
],
"metrics": [
{
"category": "AllMetrics",
"enabled": True,
"retention_policy": {
"enabled": True,
"days": 90,
},
},
],
}
try:
result = monitor.diagnostic_settings.create_or_update(
resource_uri=resource_id,
name=f"{resource_name}-forensic-logging",
parameters=diagnostic_settings,
)
return {
"status": "configured",
"resource": resource_name,
"setting_name": f"{resource_name}-forensic-logging",
}
except Exception as e:
return {"status": "error", "error": str(e)}Bewijsbehoud op Azure
Maak bij het bewaren van bewijs uit Azure AI-diensten gebruik van de ingebouwde mogelijkheden van Azure voor immutable storage en langetermijnbewaring. Configureer immutable blob storage-beleidsregels op de storage-accounts die worden gebruikt voor de archivering van diagnostische logs. Dit voorkomt verwijdering of wijziging van logdata, zelfs door beheerders, en biedt zo een fraudebestendige bewijsopslag.
Voor Azure OpenAI-onderzoeken is het meest cruciale bewijs de prompt- en response-inhoud die in Log Analytics is opgeslagen. Log Analytics heeft voor de meeste tiers een standaardbewaring van 30 dagen, wat onvoldoende is voor forensische onderzoeken. Configureer data-exportregels om AI-gerelateerde logdata continu te exporteren naar een Storage Account met immutable storage ingeschakeld en een bewaarperiode van minstens één jaar.
Bewaar voor onderzoeken naar Azure ML-workspaces de run-geschiedenis, de staat van het modelregister en de compute-logs van de workspace. Gebruik de Azure ML SDK om programmatisch run-details, metadata van modelversies en omgevingsconfiguraties te exporteren. Bewaar deze exports samen met de activity logs voor een compleet bewijspakket.
Overweeg bij het werken in gereguleerde sectoren het gebruik van Azure Confidential Computing-resources voor forensische analyse om ervoor te zorgen dat de bewijsverwerking voldoet aan de databeschermingsvereisten. Customer Lockbox kan worden ingeschakeld om expliciete goedkeuring te vereisen voordat Microsoft-support toegang kan krijgen tot je AI-resources, wat relevant is wanneer het onderzoek mogelijke insider threats betreft.
Cross-service-correlatie op Azure
Het correlatie-ID-systeem van Azure biedt een krachtig mechanisme voor het volgen van verzoeken over dienstgrenzen heen. Elke operatie in Azure genereert een correlatie-ID die gerelateerde gebeurtenissen koppelt over de Activity Log, diagnostische logs en Entra ID-aanmeldlogs heen. Bij het onderzoeken van een keten van acties (bijv. een aanvaller authenticeert via Entra ID, benadert Key Vault om een API-sleutel op te halen en roept vervolgens Azure OpenAI aan), verbindt de correlatie-ID deze gebeurtenissen, ook al strekken ze zich uit over verschillende diensten.
Gebruik Log Analytics-workbook-queries die over logtabellen heen joinen met behulp van correlatie-ID's om een uniforme tijdlijn op te bouwen. De Activity Log-tabel (AzureActivity), Entra ID-aanmeldlogs (SigninLogs), Key Vault-diagnostische logs (AzureDiagnostics waar ResourceProvider == "MICROSOFT.KEYVAULT") en Cognitive Services-diagnostische logs kunnen op deze manier allemaal worden gecorreleerd.
Daarnaast kan Azure Sentinel (nu Microsoft Sentinel) deze signalen automatisch correleren met behulp van de ingebouwde UEBA-mogelijkheden (User and Entity Behavior Analytics). Als je organisatie Sentinel gebruikt, configureer dan dataconnectoren voor alle AI-gerelateerde diensten, zodat AI-beveiligingsincidenten profiteren van de correlatie- en onderzoekstools van Sentinel.
Belangrijkste aanbevelingen
- Schakel diagnostische logging in op alle Azure OpenAI-resources met RequestResponse-logs die naar zowel Log Analytics (voor realtime queries) als een Storage Account (voor langetermijnbewaring) worden gestuurd.
- Configureer de diagnostische instellingen van de Azure ML-workspace om de categorieën AmlComputeClusterEvent, AmlRunStatusChangedEvent en AmlEnvironmentEvent vast te leggen.
- Schakel Azure Entra ID-aanmeld- en auditlogs in om AI-diensttoegang te correleren met authenticatiegebeurtenissen.
- Stel de Log Analytics-bewaring in op minstens 90 dagen voor operationele data en archiveer naar storage voor langere periodes.
- Configureer Azure Alerts op risicovolle operaties: modeluitrollen, wijzigingen in het contentbeleid en ongebruikelijke API-call-volumes.
- Gebruik Managed Identities in plaats van API-sleutels waar mogelijk. Managed identities creëren rijkere auditsporen in Entra ID.
Integratie met Microsoft Defender for Cloud
Microsoft Defender for Cloud biedt mogelijkheden voor de bescherming van AI-workloads die handmatig forensisch onderzoek aanvullen. Defender for Cloud monitort Azure-resources op beveiligingsmisconfiguraties, detecteert dreigingen in bijna realtime en genereert uitvoerbare beveiligingsaanbevelingen. Voor Azure AI-diensten kan Defender blootgestelde API-sleutels, verkeerd geconfigureerde netwerktoegang (AI-diensten die zonder beperkingen vanaf het publieke internet bereikbaar zijn) en afwijkende gebruikspatronen van diensten detecteren.
Controleer bij het onderzoeken van een Azure AI-incident de Defender for Cloud-meldingen voor de getroffen resources. De meldingstijdlijn van Defender kan voorafgaande activiteit onthullen die wel werd gedetecteerd maar waarop niet werd gehandeld, zoals mislukte authenticatiepogingen of API-calls met een verkenningspatroon die voorafgingen aan de hoofdaanval. De attack path-analyse van Defender kan tonen hoe de aanvaller van een initiële voet aan de grond naar de AI-dienst had kunnen bewegen, wat waardevol is voor het identificeren van de grondoorzaak.
Configureer de continue export van Defender for Cloud om beveiligingsmeldingen naar een Log Analytics-workspace of Event Hub te sturen. Dit zorgt ervoor dat Defender-bevindingen beschikbaar zijn voor forensische analyse naast de diagnostische logs van AI-diensten, waardoor correlatie tussen beveiligingsmeldingen en AI-dienstactiviteit in één query-omgeving mogelijk wordt.
Referenties
- Microsoft (2025). "Monitor Azure OpenAI Service." https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/monitoring
- Microsoft (2025). "Monitor Azure Machine Learning." https://learn.microsoft.com/en-us/azure/machine-learning/monitor-azure-machine-learning
- Microsoft (2025). "Azure diagnostic settings." https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/diagnostic-settings