5 min read
Azure Security Center and Microsoft Defender: Unified Cloud Security
Azure Security Center (now part of Microsoft Defender for Cloud) provides unified security management and threat protection across hybrid cloud workloads. Let’s explore how to configure and leverage its capabilities.
Understanding the Components
Microsoft Defender for Cloud includes:
- CSPM (Cloud Security Posture Management): Free tier with security recommendations
- CWP (Cloud Workload Protection): Paid plans for threat detection
Defender plans available:
- Defender for Servers
- Defender for App Service
- Defender for Storage
- Defender for SQL
- Defender for Kubernetes
- Defender for Container Registries
- Defender for Key Vault
Enabling Defender Plans
# Enable Defender for Servers
az security pricing create \
--name VirtualMachines \
--tier Standard
# Enable Defender for Storage
az security pricing create \
--name StorageAccounts \
--tier Standard
# Enable Defender for SQL
az security pricing create \
--name SqlServers \
--tier Standard
# Enable Defender for Kubernetes
az security pricing create \
--name KubernetesService \
--tier Standard
# Check enabled plans
az security pricing list --output table
Security Policies and Initiatives
Apply security policies via Azure Policy:
# Assign Azure Security Benchmark initiative
az policy assignment create \
--name "Azure Security Benchmark" \
--scope /subscriptions/<subscription-id> \
--policy-set-definition /providers/Microsoft.Authorization/policySetDefinitions/1f3afdf9-d0c9-4c3d-847f-89da613e70a8
# Create custom security policy
az policy definition create \
--name "Require-SQL-TDE" \
--display-name "Require TDE on SQL Databases" \
--description "Ensures Transparent Data Encryption is enabled" \
--rules '{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Sql/servers/databases"
},
{
"field": "Microsoft.Sql/servers/databases/transparentDataEncryption.status",
"notEquals": "Enabled"
}
]
},
"then": {
"effect": "deny"
}
}'
Working with Recommendations
Query recommendations programmatically:
from azure.identity import DefaultAzureCredential
from azure.mgmt.security import SecurityCenter
credential = DefaultAzureCredential()
client = SecurityCenter(credential, subscription_id, asc_location="centralus")
# Get all recommendations
recommendations = client.recommendations.list()
for rec in recommendations:
if rec.state == "Unhealthy":
print(f"Resource: {rec.resource_details.id}")
print(f"Recommendation: {rec.display_name}")
print(f"Severity: {rec.severity}")
print(f"Remediation: {rec.remediation_description}")
print("---")
# Get recommendation by ID
rec = client.recommendations.get(
resource_id="/subscriptions/.../resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/vm1",
recommendation_id="recommendation-guid"
)
Automated Remediation
Create workflow automation for auto-remediation:
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"triggers": {
"When_an_Azure_Security_Center_Recommendation_is_created_or_triggered": {
"type": "ApiConnectionWebhook",
"inputs": {
"body": {
"callback_url": "@{listCallbackUrl()}"
},
"host": {
"connection": {
"name": "@parameters('$connections')['ascassessment']['connectionId']"
}
},
"path": "/Microsoft.Security/Recommendations/subscribe"
}
}
},
"actions": {
"Condition_Check_Recommendation_Type": {
"type": "If",
"expression": {
"and": [
{
"equals": [
"@triggerBody()?['properties']?['displayName']",
"Storage account should use a private link connection"
]
}
]
},
"actions": {
"Enable_Private_Endpoint": {
"type": "ApiConnection",
"inputs": {
"host": {
"connection": {
"name": "@parameters('$connections')['arm']['connectionId']"
}
},
"method": "put",
"path": "/subscriptions/@{triggerBody()?['properties']?['resourceDetails']?['id']}/providers/Microsoft.Network/privateEndpoints/storage-pe",
"body": {
"location": "eastus",
"properties": {
"privateLinkServiceConnections": [
{
"name": "storage-connection",
"properties": {
"privateLinkServiceId": "@{triggerBody()?['properties']?['resourceDetails']?['id']}",
"groupIds": ["blob"]
}
}
],
"subnet": {
"id": "/subscriptions/.../subnets/private-endpoints"
}
}
}
}
}
}
}
}
}
}
Defender for Servers
Configure Defender for Servers features:
# Enable auto-provisioning of Log Analytics agent
az security auto-provisioning-setting update \
--name default \
--auto-provision On
# Configure vulnerability assessment
az security va sql baseline set \
--resource-group my-rg \
--server-name my-sql-server \
--database-name my-database \
--workspace-id /subscriptions/.../workspaces/security-workspace
Query server vulnerabilities:
// Find VMs with critical vulnerabilities
SecurityRecommendation
| where RecommendationDisplayName contains "vulnerability"
| where RecommendationState == "Unhealthy"
| extend Severity = tostring(parse_json(ExtendedProperties).Severity)
| where Severity == "Critical"
| project
ResourceId,
RecommendationDisplayName,
Severity,
RemediationDescription
Defender for Containers
Secure your Kubernetes workloads:
# Enable Defender for AKS
az aks update \
--name my-aks-cluster \
--resource-group my-rg \
--enable-defender
# Check Defender profile
az aks show \
--name my-aks-cluster \
--resource-group my-rg \
--query securityProfile
Monitor container security:
// Container security alerts
SecurityAlert
| where ProviderName == "Azure Security Center"
| where ResourceType == "Kubernetes Service"
| project
TimeGenerated,
AlertName,
AlertSeverity,
Description,
RemediationSteps,
Entities
| order by TimeGenerated desc
Just-In-Time VM Access
Configure JIT access for secure VM management:
from azure.mgmt.security import SecurityCenter
# Get JIT policies
jit_policies = client.jit_network_access_policies.list()
# Create JIT policy
policy = {
"kind": "Basic",
"properties": {
"virtualMachines": [
{
"id": "/subscriptions/.../virtualMachines/secure-vm",
"ports": [
{
"number": 22,
"protocol": "TCP",
"allowedSourceAddressPrefix": "*",
"maxRequestAccessDuration": "PT3H"
},
{
"number": 3389,
"protocol": "TCP",
"allowedSourceAddressPrefix": "*",
"maxRequestAccessDuration": "PT3H"
}
]
}
]
}
}
client.jit_network_access_policies.create_or_update(
resource_group_name="my-rg",
asc_location="centralus",
jit_network_access_policy_name="default",
body=policy
)
# Request JIT access
request = {
"virtualMachines": [
{
"id": "/subscriptions/.../virtualMachines/secure-vm",
"ports": [
{
"number": 22,
"allowedSourceAddressPrefix": "203.0.113.10",
"endTimeUtc": "2021-05-18T15:00:00Z"
}
]
}
]
}
client.jit_network_access_policies.initiate(
resource_group_name="my-rg",
asc_location="centralus",
jit_network_access_policy_name="default",
body=request
)
Security Score
Track and improve your security score:
# Get secure score
secure_scores = client.secure_scores.list()
for score in secure_scores:
print(f"Score: {score.current_score}/{score.max_score}")
print(f"Percentage: {score.percentage}%")
# Get score by control
controls = client.secure_score_controls.list()
for control in controls:
print(f"Control: {control.display_name}")
print(f"Score: {control.current_score}/{control.max_score}")
print(f"Unhealthy resources: {control.unhealthy_resource_count}")
Continuous Export
Export security data to external systems:
# Export to Log Analytics
az security automation create \
--name "export-to-la" \
--resource-group security-rg \
--scopes '[{"scopePath": "/subscriptions/<subscription-id>"}]' \
--sources '[
{"eventSource": "Alerts"},
{"eventSource": "Recommendations"},
{"eventSource": "SecureScores"}
]' \
--actions '[{
"actionType": "LogicApp",
"logicAppResourceId": "/subscriptions/.../logicApps/export-to-la",
"uri": "https://..."
}]'
# Export to Event Hub
az security automation create \
--name "export-to-eventhub" \
--resource-group security-rg \
--scopes '[{"scopePath": "/subscriptions/<subscription-id>"}]' \
--sources '[{"eventSource": "Alerts"}]' \
--actions '[{
"actionType": "EventHub",
"eventHubResourceId": "/subscriptions/.../eventhubs/security-alerts",
"connectionString": "..."
}]'