Security Monitoring¶
Home | Solutions | Real-Time Analytics | Security Monitoring
Security monitoring and threat detection for real-time analytics infrastructure.
Overview¶
Security monitoring provides:
- Real-time threat detection
- Compliance monitoring
- Access anomaly detection
- Security incident alerting
Architecture¶
flowchart TB
subgraph "Data Sources"
AAD[Azure AD Logs]
Activity[Activity Logs]
Diagnostic[Diagnostic Logs]
Network[NSG Flow Logs]
end
subgraph "Collection"
LAW[Log Analytics Workspace]
Sentinel[Microsoft Sentinel]
end
subgraph "Detection"
Analytics[Analytics Rules]
ML[ML-Based Detection]
Threat[Threat Intelligence]
end
subgraph "Response"
Alerts[Security Alerts]
Playbooks[Automation Playbooks]
SOAR[SOAR Integration]
end
AAD --> LAW
Activity --> LAW
Diagnostic --> LAW
Network --> LAW
LAW --> Sentinel
Sentinel --> Analytics
Sentinel --> ML
Sentinel --> Threat
Analytics --> Alerts
ML --> Alerts
Alerts --> Playbooks
Playbooks --> SOAR Implementation¶
Step 1: Enable Diagnostic Logging¶
# Enable diagnostics for Event Hubs
az monitor diagnostic-settings create \
--name "security-diagnostics" \
--resource "/subscriptions/.../eventhubs/eh-analytics" \
--workspace "/subscriptions/.../workspaces/law-security" \
--logs '[{"category": "ArchiveLogs", "enabled": true}, {"category": "OperationalLogs", "enabled": true}, {"category": "AutoScaleLogs", "enabled": true}]' \
--metrics '[{"category": "AllMetrics", "enabled": true}]'
# Enable diagnostics for Stream Analytics
az monitor diagnostic-settings create \
--name "security-diagnostics" \
--resource "/subscriptions/.../streamingjobs/asa-analytics" \
--workspace "/subscriptions/.../workspaces/law-security" \
--logs '[{"category": "Execution", "enabled": true}, {"category": "Authoring", "enabled": true}]'
# Enable diagnostics for Data Lake
az monitor diagnostic-settings create \
--name "security-diagnostics" \
--resource "/subscriptions/.../storageAccounts/datalake" \
--workspace "/subscriptions/.../workspaces/law-security" \
--logs '[{"category": "StorageRead", "enabled": true}, {"category": "StorageWrite", "enabled": true}, {"category": "StorageDelete", "enabled": true}]'
Step 2: Security Detection Rules¶
// Suspicious data access pattern
StorageBlobLogs
| where TimeGenerated > ago(1h)
| where OperationName in ("GetBlob", "ListBlobs")
| summarize
AccessCount = count(),
UniqueFiles = dcount(Uri),
DataTransferred = sum(ResponseBodySize)
by CallerIpAddress, UserAgentHeader, bin(TimeGenerated, 5m)
| where AccessCount > 1000 or UniqueFiles > 500 or DataTransferred > 10737418240
| project
TimeGenerated,
CallerIpAddress,
UserAgentHeader,
AccessCount,
UniqueFiles,
DataTransferred,
AlertType = "SuspiciousDataAccess"
// Failed authentication attempts
SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType != 0
| summarize
FailedAttempts = count(),
DistinctUsers = dcount(UserPrincipalName),
Applications = make_set(AppDisplayName)
by IPAddress, bin(TimeGenerated, 10m)
| where FailedAttempts > 10
| project
TimeGenerated,
IPAddress,
FailedAttempts,
DistinctUsers,
Applications,
AlertType = "BruteForceAttempt"
// Privileged operation anomaly
AzureActivity
| where TimeGenerated > ago(24h)
| where CategoryValue == "Administrative"
| where OperationNameValue has_any ("delete", "write", "action")
| summarize
Operations = count(),
UniqueResources = dcount(ResourceId),
OperationTypes = make_set(OperationNameValue)
by Caller, bin(TimeGenerated, 1h)
| where Operations > 50
| project
TimeGenerated,
Caller,
Operations,
UniqueResources,
OperationTypes,
AlertType = "ExcessivePrivilegedOperations"
Step 3: Sentinel Analytics Rules¶
{
"kind": "Scheduled",
"properties": {
"displayName": "Data Exfiltration Detection",
"description": "Detects potential data exfiltration from storage accounts",
"severity": "High",
"enabled": true,
"query": "StorageBlobLogs\n| where OperationName == 'GetBlob'\n| where CallerIpAddress !startswith '10.' and CallerIpAddress !startswith '192.168.'\n| summarize TotalBytes = sum(ResponseBodySize), FileCount = count() by CallerIpAddress, bin(TimeGenerated, 1h)\n| where TotalBytes > 5368709120",
"queryFrequency": "PT1H",
"queryPeriod": "PT1H",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0,
"tactics": ["Exfiltration"],
"techniques": ["T1567"]
}
}
Step 4: Automated Response Playbooks¶
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"triggers": {
"Microsoft_Sentinel_alert": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"path": "/subscribe"
}
}
},
"actions": {
"Get_Alert_Details": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"method": "get",
"path": "/alerts/@{triggerBody()?['SystemAlertId']}"
}
},
"Block_IP_If_Malicious": {
"type": "If",
"expression": {
"equals": ["@body('Get_Alert_Details')?['AlertType']", "BruteForceAttempt"]
},
"actions": {
"Add_IP_to_Block_List": {
"type": "ApiConnection",
"inputs": {
"method": "post",
"path": "/firewallRules",
"body": {
"ipAddress": "@body('Get_Alert_Details')?['IPAddress']",
"action": "Block"
}
}
}
}
},
"Create_Incident": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['azuresentinel']['connectionId']"
}
},
"method": "put",
"path": "/incidents",
"body": {
"title": "@body('Get_Alert_Details')?['AlertDisplayName']",
"severity": "@body('Get_Alert_Details')?['Severity']",
"status": "New"
}
}
},
"Notify_Security_Team": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['teams']['connectionId']"
}
},
"method": "post",
"path": "/v3/beta/teams/.../channels/.../messages",
"body": {
"body": {
"content": "Security Alert: @{body('Get_Alert_Details')?['AlertDisplayName']}"
}
}
}
}
}
}
}
Step 5: Security Dashboard¶
// Security overview dashboard
let timeRange = 24h;
// Alert summary
let alertSummary = SecurityAlert
| where TimeGenerated > ago(timeRange)
| summarize
TotalAlerts = count(),
HighSeverity = countif(AlertSeverity == "High"),
MediumSeverity = countif(AlertSeverity == "Medium")
by bin(TimeGenerated, 1h);
// Access anomalies
let accessAnomalies = StorageBlobLogs
| where TimeGenerated > ago(timeRange)
| summarize AccessCount = count() by CallerIpAddress, bin(TimeGenerated, 1h)
| where AccessCount > 100;
// Failed authentications
let authFailures = SigninLogs
| where TimeGenerated > ago(timeRange)
| where ResultType != 0
| summarize Failures = count() by bin(TimeGenerated, 1h);
// Combine for dashboard
alertSummary
| join kind=leftouter accessAnomalies on TimeGenerated
| join kind=leftouter authFailures on TimeGenerated
| project
TimeGenerated,
TotalAlerts,
HighSeverity,
MediumSeverity,
AccessAnomalyCount = coalesce(AccessCount, 0),
AuthFailures = coalesce(Failures, 0)
Compliance Monitoring¶
// Data access audit for compliance
StorageBlobLogs
| where TimeGenerated > ago(30d)
| where Uri contains "pii" or Uri contains "sensitive"
| summarize
AccessCount = count(),
UniqueUsers = dcount(RequesterObjectId),
Operations = make_set(OperationName)
by Uri, bin(TimeGenerated, 1d)
| project
Date = TimeGenerated,
DataAsset = Uri,
AccessCount,
UniqueUsers,
Operations
| order by Date desc
Related Documentation¶
Last Updated: January 2025