On This Page
1Overview2Architecture Overview
3Azure Service Topology4Implementation Guide
5Decision Criteria6Cost Model
7Anti-Patterns to Avoid8References

Overview

The Azure security baseline is a layered control set applied consistently across every production subscription. Microsoft Entra ID governs the identity plane through Managed Identities, Conditional Access policies, and Privileged Identity Management. Azure Key Vault stores every secret, certificate, and encryption key — applications reference them via Key Vault references without ever handling the raw value. Private Endpoints pull PaaS services onto your virtual network so traffic never traverses the public internet. Azure Policy enforces guardrails at deployment time, with audit mode preceding deny mode to surface violations before they block delivery. Microsoft Defender for Cloud provides continuous posture measurement against the Microsoft Cloud Security Benchmark and feeds findings into Microsoft Sentinel for SIEM/SOAR response.

Architecture Overview

%%{init:{'theme':'base','themeVariables':{'fontSize':'14px','fontFamily':'Inter, system-ui, sans-serif','primaryColor':'#DBEAFE','primaryTextColor':'#1e3a5f','primaryBorderColor':'#2563EB','lineColor':'#374151','clusterBkg':'#F9FAFB','clusterBorder':'#D1D5DB','edgeLabelBackground':'#FFFFFF'},'flowchart':{'curve':'orthogonal','padding':30,'nodeSpacing':65,'rankSpacing':75,'useMaxWidth':true}}}%% flowchart TD START([Azure Subscription with Workloads]) subgraph IDENTITY["Identity Domain"] ENTRA[Microsoft Entra ID\nManaged Identities\nConditional Access + MFA] PIM[Privileged Identity\nManagement\nJust-in-time elevation] end subgraph NETWORK["Network Domain"] PE[Private Endpoints\nPaaS onto VNet\nPublic access disabled] FW[Azure Firewall\nEgress filtering\nThreat intelligence] end subgraph DATA["Data Domain"] KV[Key Vault Premium HSM\nSecrets, certs, keys\nKey Vault references only] CMK[Customer-Managed Keys\nCMK + TDE on databases\nKey rotation automated] end subgraph OPS["Operations Domain"] DFC[Defender for Cloud\nMCSB posture score\nFoundational CSPM free] SENT[Microsoft Sentinel\nCloud SIEM/SOAR\nFusion threat detection] end DONE([Continuous Zero Trust Posture]) START --> IDENTITY START --> NETWORK IDENTITY --> DATA NETWORK --> DATA DATA --> OPS OPS --> DONE style START fill:#4f8ef7,color:#fff style DONE fill:#10b981,color:#fff style DFC fill:#e0f2fe style SENT fill:#e0f2fe

Azure Service Topology

%%{init:{'theme':'base','themeVariables':{'fontSize':'14px','fontFamily':'Inter, system-ui, sans-serif','primaryColor':'#DBEAFE','primaryTextColor':'#1e3a5f','primaryBorderColor':'#2563EB','lineColor':'#374151','clusterBkg':'#F9FAFB','clusterBorder':'#D1D5DB','edgeLabelBackground':'#FFFFFF'},'flowchart':{'curve':'orthogonal','padding':30,'nodeSpacing':65,'rankSpacing':75,'useMaxWidth':true}}}%% flowchart TD WORKLOAD[Application Workload] subgraph ID_PLANE["Identity Plane — Microsoft Entra ID"] MI[Managed Identity\nNo client secrets\nAutomatic token refresh] CA[Conditional Access\nMFA + device compliance\nLocation-based policy] PIM_T[Privileged Identity\nManagement\nTime-bounded elevation] end subgraph NET_PLANE["Network Plane"] AFW[Azure Firewall\nCentralised egress\nFQDN + IP rules] PE_T[Private Endpoints\nPaaS on private IP\nPublic network access Disabled] NSG[NSG + ASG\nSubnet-level rules\nApplication security groups] end subgraph DATA_PLANE["Data Plane"] KV_T[Key Vault Premium HSM\nRBAC authorisation\nSoft delete 90d + purge protection] CMK_T[CMK + TDE\nStorage service encryption\nDatabase transparent encryption] end subgraph OPS_PLANE["Operations Plane"] DFC_T[Defender for Cloud\nMCSB secure score\nAttack path analysis] LOG[Log Analytics Workspace\nCentralised log sink\nRetention 90 days+] SENT_T[Microsoft Sentinel\nFusion analytics\nPlaybook auto-response] end WORKLOAD --> MI MI --> KV_T KV_T --> CMK_T WORKLOAD --> PE_T PE_T --> NET_PLANE AFW --> SENT_T NSG --> LOG DFC_T --> SENT_T LOG --> SENT_T SENT_T --> ALERT{Finding Severity} ALERT -->|High or Critical| PAGE[Immediate Response\nIncident ticket created\nSecurity team notified] ALERT -->|Medium| REVIEW[Triage Queue\nWeekly review cycle\nTeam acknowledgement] ALERT -->|Low or Informational| TRACK[Log and Track\nMonthly review\nSuppression if accepted risk] style WORKLOAD fill:#4f8ef7,color:#fff style PAGE fill:#fef3c7 style ALERT fill:#e0f2fe

Implementation Guide

Bicep — Key Vault with Private Endpoint and RBAC

// Key Vault — Premium SKU with HSM, RBAC auth, soft delete enforced
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: 'kv-${workloadName}-${environment}'
  location: location
  properties: {
    sku: {
      family: 'A'
      name: 'premium'         // HSM-backed keys
    }
    tenantId: subscription().tenantId
    enableRbacAuthorization: true       // RBAC over access policies
    enableSoftDelete: true
    softDeleteRetentionInDays: 90
    enablePurgeProtection: true         // Cannot be reversed once set
    publicNetworkAccess: 'Disabled'
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'AzureServices'
    }
  }
}

// Private endpoint — brings Key Vault onto the VNet
resource kvPrivateEndpoint 'Microsoft.Network/privateEndpoints@2023-05-01' = {
  name: 'pe-${keyVault.name}'
  location: location
  properties: {
    subnet: { id: privateEndpointSubnetId }
    privateLinkServiceConnections: [
      {
        name: 'kvConnection'
        properties: {
          privateLinkServiceId: keyVault.id
          groupIds: [ 'vault' ]
        }
      }
    ]
  }
}

// Role assignment — grant Function App Managed Identity read access to secrets
resource kvSecretsUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(keyVault.id, functionAppPrincipalId, '4633458b-17de-408a-b874-0445c86b69e6')
  scope: keyVault
  properties: {
    roleDefinitionId: subscriptionResourceId(
      'Microsoft.Authorization/roleDefinitions',
      '4633458b-17de-408a-b874-0445c86b69e6'  // Key Vault Secrets User
    )
    principalId: functionAppPrincipalId
    principalType: 'ServicePrincipal'
  }
}

Terraform equivalent: Use azurerm_key_vault with enable_rbac_authorization = true, purge_protection_enabled = true, soft_delete_retention_days = 90, and network_acls { default_action = "Deny" bypass = "AzureServices" }. Pair with azurerm_private_endpoint (subresource_names ["vault"]) and azurerm_role_assignment using role definition id 4633458b-17de-408a-b874-0445c86b69e6.

Bicep — Azure Policy Assignment (Audit Mode First)

// Assign CIS Microsoft Azure Foundations Benchmark at subscription scope
// Use DoNotEnforce (audit) first; switch to Enabled after remediating findings
resource cisPolicyAssignment 'Microsoft.Authorization/policyAssignments@2023-04-01' = {
  name: 'cis-azure-foundations-v210'
  scope: subscription()
  location: location
  identity: {
    type: 'SystemAssigned'   // Required for deployIfNotExists / modify effects
  }
  properties: {
    displayName: 'CIS Microsoft Azure Foundations Benchmark v2.1.0'
    policyDefinitionId: '/providers/Microsoft.Authorization/policySetDefinitions/'
      + '612b5213-9160-4969-8578-1518bd2a000c'   // Built-in initiative ID
    enforcementMode: 'DoNotEnforce'              // Audit first, deny later
    parameters: {}
  }
}

Terraform equivalent: Use azurerm_subscription_policy_assignment with enforce = false initially. The built-in initiative ID 612b5213-9160-4969-8578-1518bd2a000c targets the CIS Azure Foundations Benchmark v2.1.0. Switch enforce = true after the secure score remediation cycle completes.

Bicep — Managed Identity on Function App

// Function App with system-assigned Managed Identity — no client secrets
resource functionApp 'Microsoft.Web/sites@2023-01-01' = {
  name: 'func-${workloadName}-${environment}'
  location: location
  kind: 'functionapp'
  identity: {
    type: 'SystemAssigned'    // Platform manages the credential lifecycle
  }
  properties: {
    siteConfig: {
      appSettings: [
        {
          // Key Vault reference — app never sees the raw secret value
          name: 'ConnectionString'
          value: '@Microsoft.KeyVault(VaultName=${keyVault.name};SecretName=db-connection-string)'
        }
        {
          name: 'FUNCTIONS_EXTENSION_VERSION'
          value: '~4'
        }
      ]
    }
  }
}

Terraform equivalent: Set identity { type = "SystemAssigned" } on azurerm_linux_function_app. Reference secrets via @Microsoft.KeyVault(...) in app_settings rather than storing raw values. The azurerm_role_assignment for Key Vault Secrets User binds the identity[0].principal_id output to the vault scope.

Decision Criteria

Control Domain Recommended Azure Service / Pattern Without It You Miss
Workload identity Managed Identity (system-assigned) Secrets in code or config that rotate manually
Human privileged access PIM with time-bounded elevation Standing admin access exploitable anytime
Secret and key storage Key Vault Premium HSM + Key Vault references Secrets in App Settings visible in portal and logs
PaaS network isolation Private Endpoints + publicNetworkAccess Disabled PaaS reachable over public internet by any IP
Perimeter egress control Azure Firewall with threat intelligence Unconstrained outbound allowing C2 callbacks
Traffic segmentation NSG + ASG at subnet level Lateral movement unrestricted once inside VNet
Posture management Defender for Cloud (Foundational CSPM free) No visibility of misconfiguration against MCSB
Compliance enforcement Azure Policy (audit then deny) Deployments violate baseline without detection
SIEM / SOAR response Microsoft Sentinel with Fusion analytics Findings accumulate unreviewed with no playbook
Data encryption CMK + TDE on databases, service encryption on storage Platform-managed keys outside your control plane

Cost Model

Service Cost Driver Typical Monthly Cost
Defender for Cloud — Foundational CSPM Included $0 — always on, no opt-in needed
Defender for Cloud — Defender plans Per resource type (Servers $15/node, Databases $15/server) $150–800 per subscription
Microsoft Sentinel GB ingested into Log Analytics $150–600 per subscription
Key Vault Premium Operations + HSM-backed keys ($1.00/key/month) $20–80 per vault
Azure Firewall Deployment hour + data processed $900–1,500 per firewall instance
Private Endpoints Per endpoint + data processed ($0.01/GB) $15–60 per endpoint
Azure Policy Built-in initiatives $0 — no charge for policy evaluation

Cost optimisation levers:

  • Defender for Cloud Foundational CSPM is free and should be enabled on every subscription with no exception — enabling it costs nothing and surfaces the MCSB secure score.
  • Enable enhanced Defender plans selectively: prioritise Defender for Servers and Defender for SQL on internet-facing and data-tier workloads before enabling all plans.
  • Right-size Log Analytics retention: 90-day interactive retention is included in Sentinel pricing; archive tier at $0.023/GB/month covers compliance requirements beyond 90 days.
  • Use a single centralised Log Analytics workspace per region to consolidate Sentinel ingestion and avoid per-workspace duplication costs.
  • Review Azure Firewall rule hit counts monthly and remove unused FQDN rules to reduce policy complexity without affecting cost directly; consider Azure Firewall Basic ($300/month) for non-production subscriptions.
  • Scope Defender for Databases to production servers only; exclude dev and test resources via exclusion lists in the Defender for Cloud settings blade.

Anti-Patterns to Avoid

⚠ 1. Service Principal with Client Secret for Workload Authentication

Issuing a service principal client secret so an application can call Azure APIs or access storage. Secrets expire, must be rotated manually, and are frequently hardcoded in environment variables or committed to source control. Every rotation is a deployment event.

Hover to see the fix ↻
↺ Correct Approach

Use a system-assigned Managed Identity on the compute resource (App Service, Function App, Container App, AKS pod via Workload Identity Federation). The platform issues and rotates the token automatically. The identity has no exportable credential.

⚠ 2. Public Network Access Enabled on PaaS Services

Deploying Azure Storage, Azure SQL, Azure Service Bus, or Azure Key Vault with public network access set to Enabled (the default). Any IP on the internet can attempt authentication against the public endpoint, and misconfigured firewall rules or public blobs become immediately reachable.

Hover to see the fix ↻
↺ Correct Approach

Create a Private Endpoint for every PaaS service in production and set publicNetworkAccess: 'Disabled'. Traffic routes over the Microsoft backbone via private IP. Pair with a Policy deny assignment to prevent future resources from being deployed publicly.

⚠ 3. Connection Strings in App Settings

Storing database connection strings, storage account keys, or API tokens directly in App Service or Function App application settings. The values appear in plaintext in the Azure Portal, are included in deployment exports, and are accessible to anyone with Contributor rights on the app.

Hover to see the fix ↻
↺ Correct Approach

Store every secret in Key Vault and reference it via a Key Vault reference (@Microsoft.KeyVault(VaultName=...;SecretName=...)). The runtime resolves the reference at startup; the application code and all portal views show only the reference string, never the value. Enable enableRbacAuthorization: true and grant only Key Vault Secrets User.

⚠ 4. Soft Delete Disabled on Key Vault

Creating a Key Vault without soft delete, or with soft delete enabled but purge protection disabled. Accidental or malicious deletion of a vault or individual secrets is immediately permanent and unrecoverable. This is a common cause of data loss during subscription cleanups.

Hover to see the fix ↻
↺ Correct Approach

Enable soft delete with 90-day retention and enable purge protection on every Key Vault. Once purge protection is set, neither the vault owner nor Microsoft support can purge the vault during the retention window. Note that these settings cannot be disabled once enabled — treat that as a feature.

⚠ 5. No Defender for Cloud on Subscriptions

Relying on Azure's default security without enabling Defender for Cloud, leaving the MCSB posture score at zero and misconfiguration findings invisible. Teams discover issues only during audits or after a breach, rather than continuously.

Hover to see the fix ↻
↺ Correct Approach

Defender for Cloud Foundational CSPM is free and enabled at the subscription level with no per-resource charge. Enable it on every subscription immediately. It surfaces the MCSB secure score, provides attack path analysis, and integrates with Microsoft Sentinel without additional ingestion cost for Defender findings.

Flowchart

%%{init:{'theme':'base','themeVariables':{'fontSize':'14px','fontFamily':'Inter, system-ui, sans-serif','primaryColor':'#DBEAFE','primaryTextColor':'#1e3a5f','primaryBorderColor':'#2563EB','lineColor':'#374151','clusterBkg':'#F9FAFB','clusterBorder':'#D1D5DB','edgeLabelBackground':'#FFFFFF'},'flowchart':{'curve':'orthogonal','padding':30,'nodeSpacing':65,'rankSpacing':75,'useMaxWidth':true}}}%% flowchart TD START([New Production Azure Subscription]) START --> IDENTITY[Identity Baseline\nEnable Managed Identities\nConfigure Conditional Access\nActivate PIM for admins] IDENTITY --> ENABLE[Deploy Core Security Services] ENABLE --> KV_B[Key Vault Premium HSM\nSoft delete 90d + purge protection\nRBAC authorisation enabled\nPublic access disabled] ENABLE --> PE_B[Private Endpoints\nAll PaaS services\nPublic network access Disabled] ENABLE --> POL_B[Azure Policy\nCIS Azure Foundations v2.1.0\nDoNotEnforce audit first] KV_B & PE_B & POL_B --> DFC_B[Defender for Cloud\nFoundational CSPM — free\nEnable Defender plans per tier\nMCSB secure score baseline] DFC_B --> SENT_B[Microsoft Sentinel\nConnect Defender for Cloud\nFusion analytics enabled\nPlaybooks for auto-response] SENT_B --> ALERT_B{Finding Severity} ALERT_B -->|High or Critical| PAGE_B[Immediate Response\nSecurity team paged\nIncident ticket opened] ALERT_B -->|Medium| REVIEW_B[Triage Queue\nWeekly review cycle\nTeam acknowledgement] ALERT_B -->|Low or Informational| LOG_B[Log and Track\nMonthly review\nSuppression if accepted risk] PAGE_B & REVIEW_B & LOG_B --> DONE([Subscription Meets Azure Security Baseline]) style START fill:#4f8ef7,color:#fff style DONE fill:#10b981,color:#fff style PAGE_B fill:#fef3c7 style ALERT_B fill:#e0f2fe style DFC_B fill:#e0f2fe

References

  1. Microsoft Cloud Security Benchmark. https://learn.microsoft.com/security/benchmark/azure/
  2. Managed Identities for Azure Resources. https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
  3. Azure Key Vault best practices. https://learn.microsoft.com/azure/key-vault/general/best-practices
  4. Azure Private Link overview. https://learn.microsoft.com/azure/private-link/private-link-overview
  5. Microsoft Defender for Cloud introduction. https://learn.microsoft.com/azure/defender-for-cloud/defender-for-cloud-introduction
  6. CIS Microsoft Azure Foundations Benchmark. https://www.cisecurity.org/benchmark/azure
  7. Microsoft Sentinel overview. https://learn.microsoft.com/azure/sentinel/overview
  8. Azure Policy built-in definitions. https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies
  9. Workload Identity Federation for AKS. https://learn.microsoft.com/azure/aks/workload-identity-overview
  10. Portal: AWS security baseline comparison
Ascendion Engineering Knowledge Base ← Cloud