CIS Microsoft Azure Foundations Benchmark
Secure configuration guidelines for Microsoft Azure cloud platform
v3.0.0 March 2025Overview
▶This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for Microsoft Azure. The benchmark covers identity and access management, security center settings, storage, databases, logging, networking, virtual machines, key vault, and app services.
| Section | Area | Focus |
|---|---|---|
| 1 | Identity and Access Management | Entra ID, Conditional Access, MFA, PIM, Guest Access |
| 2 | Microsoft Defender for Cloud | Defender Plans, Security Contacts, Auto-provisioning |
| 3 | Storage Accounts | Secure Transfer, Encryption, Access Keys, SAS Tokens |
| 4 | Database Services | Azure SQL, PostgreSQL, MySQL, Cosmos DB |
| 5 | Logging and Monitoring | Diagnostic Settings, Activity Logs, Alerts |
| 6 | Networking | NSGs, Network Watcher, VPN, Public IP |
| 7 | Virtual Machines | OS Disk Encryption, Extensions, Managed Disks |
| 8 | Key Vault | Key Management, Secrets, Certificates, RBAC |
| 9 | AppService | Authentication, TLS, Managed Identity, HTTPS |
Profile Definitions
▶| Profile | Description | Intended Use |
|---|---|---|
| L1 | Level 1 | Practical baseline security settings for all Azure subscriptions. Minimal performance impact. |
| L2 | Level 2 | Defense-in-depth settings for security-sensitive environments. May affect usability or cost. |
1 — Identity and Access Management
▶Microsoft Entra ID configuration including conditional access, multi-factor authentication, guest access, and privileged identity management.
1.1 Security Defaults & Conditional Access
▶Security Defaults provide basic identity security. However, organizations implementing Conditional Access must disable Security Defaults — the two features are mutually exclusive. Conditional Access provides more granular control.
Security Defaults cannot coexist with Conditional Access policies. Organizations with Conditional Access gain more fine-grained control over authentication flows and can enforce MFA selectively.
az rest --method GET \ --url 'https://graph.microsoft.com/v1.0/policies/identitySecurityDefaultsEnforcementPolicy' \ --query 'isEnabled' # If Conditional Access policies exist, this should be false
Navigate to Microsoft Entra admin center > Identity > Overview > Properties > Manage security defaults. Set to Disabled only after Conditional Access policies are in place.
1.2 MFA & Authentication
▶A Conditional Access policy should exist that requires MFA for all users accessing all cloud applications, excluding emergency access accounts.
Failure to multi-Factor Authentication is Required for All Users in All Applications may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
# Review Conditional Access policies in Entra admin center: # Protection > Conditional Access > Policies # Look for policy: Users=All, Apps=All Cloud Apps, Grant=Require MFA, State=On
Create a Conditional Access policy targeting All Users (excluding break-glass accounts), All Cloud Apps, with Grant control set to Require multifactor authentication.
| Control | Description | IG |
|---|---|---|
| 6.3 | Require MFA for Externally-Exposed Applications | IG1 |
| 6.5 | Require MFA for Administrative Access | IG1 |
Configure Microsoft Authenticator with number matching and additional context (application name and geographic location) to prevent MFA fatigue attacks where users are bombarded with push notifications until they approve.
Failure to that Microsoft Authenticator is Configured to Protect Against MFA Fatigue may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
Navigate to Entra admin center > Protection > Authentication methods > Microsoft Authenticator. Verify: Number matching = Enabled, Show application name = Enabled, Show geographic location = Enabled.
Enable number matching and additional context in the Microsoft Authenticator authentication method settings.
1.3 Guest & External Access
▶Restrict guest users so they can only see their own user profile. By default, guests can enumerate users, groups, and other directory objects. Set guest user access to most restrictive.
Failure to that Guest Users Have Restricted Access to Azure AD Directory may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az rest --method GET \ --url 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy' \ --query 'guestUserRoleId' # Should be: 2af84b1e-32c8-42b7-82bc-daa82404023b (most restrictive)
Navigate to External Identities > External collaboration settings. Set Guest user access restrictions to the most restrictive option.
1.4 Custom & Privileged Roles
▶Configure recurring access reviews for high-privileged roles (Global Administrator, Privileged Role Administrator, etc.) through Entra ID Governance. Reviews should be at least quarterly.
Misconfiguration of Access Reviews for High-Privileged Azure AD Roles can lead to security gaps that may be exploited by attackers. A properly configured Azure cloud platform reduces exposure to both known vulnerabilities and configuration drift.
Navigate to Identity Governance > Access Reviews. Verify reviews exist for: Global Administrator, Security Administrator, Privileged Role Administrator, Exchange Administrator, SharePoint Administrator.
Create access reviews for each high-privileged role with quarterly frequency and auto-remove on non-response.
Custom roles in Azure can have overly broad permissions. Review all custom role definitions to ensure they follow the principle of least privilege and do not grant wildcard (*) actions unnecessarily.
Failure to custom Role Assignments Are Reviewed and Minimized may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az role definition list --custom-role-only true \
--query '[].{Name:roleName, Actions:permissions[0].actions}' -o tableReview each custom role and remove unnecessary permissions. Replace wildcard actions with specific action strings.
2 — Microsoft Defender for Cloud
▶Microsoft Defender for Cloud provides unified security management and advanced threat protection across Azure workloads.
2.1 Defender Plans
▶Enable Microsoft Defender for Servers to gain threat detection for VMs including file integrity monitoring, adaptive application controls, and just-in-time VM access.
An improperly configured value for Microsoft Defender for Servers could weaken security controls or allow unintended behavior. Setting this to On ensures the Azure cloud platform operates within a well-defined security boundary.
az security pricing show -n VirtualMachines --query 'pricingTier' # Should be "Standard"
az security pricing create -n VirtualMachines --tier Standard
Enable Defender for Key Vault to detect unusual access patterns, potentially harmful operations, and suspicious activities related to key vault resources.
An improperly configured value for Microsoft Defender for Key Vault could weaken security controls or allow unintended behavior. Setting this to On ensures the Azure cloud platform operates within a well-defined security boundary.
az security pricing show -n KeyVaults --query 'pricingTier' # Should be "Standard"
az security pricing create -n KeyVaults --tier Standard
Enable Defender for Storage to detect malicious file uploads, data exfiltration, and suspicious access patterns to storage accounts.
An improperly configured value for Microsoft Defender for Storage could weaken security controls or allow unintended behavior. Setting this to On ensures the Azure cloud platform operates within a well-defined security boundary.
az security pricing show -n StorageAccounts --query 'pricingTier' # Should be "Standard"
az security pricing create -n StorageAccounts --tier Standard
2.2 Security Contacts
▶Configure security contact email addresses in Defender for Cloud to receive alert notifications. Include subscription owners and security team distribution lists.
Failure to security Alert Emails are Configured to Relevant Contacts may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az security contact list --query '[].{Email:email, AlertNotifications:alertNotifications}'
# Verify email addresses are set and alertNotifications is "On"az security contact create -n default \ --email security@yourdomain.com \ --alert-notifications On \ --alerts-to-admins On
3 — Storage Accounts
▶Configuration of Azure Storage accounts covering encryption, access control, network restrictions, and secure transfer requirements.
3.1 Secure Transfer & Encryption
▶Require secure transfer (HTTPS) for all storage account operations. This prevents data from being transmitted in clear text over HTTP.
An improperly configured value for Secure Transfer Required could weaken security controls or allow unintended behavior. Setting this to Enabled ensures the Azure cloud platform operates within a well-defined security boundary.
az storage account list --query '[].{Name:name, SecureTransfer:enableHttpsTrafficOnly}' -o table
# All should show Trueaz storage account update -n <storageAccountName> -g <resourceGroup> \ --https-only true
Enable infrastructure encryption (double encryption) for storage accounts. This adds a second layer of encryption at the infrastructure level using a platform-managed key, in addition to service-level encryption.
Without Storage Account Infrastructure Encryption enabled, the Azure cloud platform may lack critical protections against known attack vectors. Enabling this control mitigates risk and aligns the deployment with industry-accepted security baselines.
az storage account show -n <account> -g <rg> \ --query 'encryption.requireInfrastructureEncryption' # Should be true
Infrastructure encryption can only be enabled at storage account creation. Create a new storage account with --require-infrastructure-encryption true and migrate data.
Set the minimum TLS version to 1.2 for all storage accounts. TLS 1.0 and 1.1 have known vulnerabilities and should be disabled.
An improperly configured value for Minimum TLS Version could weaken security controls or allow unintended behavior. Setting this to 1.2 ensures the Azure cloud platform operates within a well-defined security boundary.
az storage account list --query '[].{Name:name, MinTLS:minimumTlsVersion}' -o table
# All should show TLS1_2az storage account update -n <account> -g <rg> --min-tls-version TLS1_2
3.2 Access Keys & SAS
▶Storage account access keys should be regenerated periodically. When keys are regenerated, applications using those keys must be updated. Consider using Entra ID authentication or managed identities instead of access keys.
Failure to storage Account Access Keys are Periodically Regenerated may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az monitor activity-log list --resource-group <rg> \ --query "[?operationName.value=='Microsoft.Storage/storageAccounts/regenerateKey/action']" \ --start-time $(date -d '90 days ago' '+%Y-%m-%dT%H:%M:%SZ')
Rotate keys every 90 days or migrate to Entra ID authentication with RBAC instead of shared keys.
Disable public network access to storage accounts and use private endpoints instead. This ensures storage traffic traverses the Microsoft backbone network rather than the public internet.
Leaving Public Network Access to Storage Accounts enabled when it is not required unnecessarily expands the attack surface. An attacker could leverage this feature to gain unauthorized access or escalate privileges on the Azure cloud platform.
az storage account list --query '[].{Name:name, PublicAccess:publicNetworkAccess}' -o table
# Should show "Disabled"az storage account update -n <account> -g <rg> --public-network-access Disabled # Then create private endpoints for required connectivity
4 — Database Services
▶Security configuration for Azure managed database services including SQL Database, PostgreSQL, and MySQL.
4.1 Azure SQL
▶Enable auditing for all Azure SQL servers. Audit logs capture database events and write them to a storage account, Log Analytics workspace, or Event Hub.
An improperly configured value for Auditing could weaken security controls or allow unintended behavior. Setting this to On for SQL Servers ensures the Azure cloud platform operates within a well-defined security boundary.
az sql server audit-policy show --resource-group <rg> --server <server> \ --query 'state' # Should be "Enabled"
az sql server audit-policy update --resource-group <rg> --server <server> \ --state Enabled \ --storage-account <storageAccountId> \ --retention-days 90
Transparent Data Encryption encrypts data at rest for Azure SQL databases. TDE is enabled by default for new databases but should be verified for all existing databases.
Failure to transparent Data Encryption (TDE) is Enabled on SQL Databases may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az sql db tde show --resource-group <rg> --server <server> --database <db> \ --query 'state' # Should be "Enabled"
az sql db tde set --resource-group <rg> --server <server> --database <db> \ --status Enabled
Ensure SQL server firewall rules do not allow access from all Azure services (0.0.0.0) or all IP addresses. Each SQL server should have specific IP ranges or use private endpoints.
Failure to no Azure SQL Databases Allow Ingress from 0.0.0.0/0 may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az sql server firewall-rule list --resource-group <rg> --server <server> \
--query '[].{Name:name, Start:startIpAddress, End:endIpAddress}' -o table
# Should NOT have 0.0.0.0 - 255.255.255.255 or 0.0.0.0 - 0.0.0.0az sql server firewall-rule delete --resource-group <rg> --server <server> \ --name AllowAllWindowsAzureIps
4.2 PostgreSQL / MySQL
▶Enable SSL enforcement on Azure Database for PostgreSQL flexible servers to ensure all client connections use TLS encryption.
An improperly configured value for Enforce SSL Connection could weaken security controls or allow unintended behavior. Setting this to ENABLED for PostgreSQL ensures the Azure cloud platform operates within a well-defined security boundary.
az postgres flexible-server parameter show --resource-group <rg> \ --server-name <server> --name require_secure_transport \ --query 'value' # Should be "ON"
az postgres flexible-server parameter set --resource-group <rg> \ --server-name <server> --name require_secure_transport --value ON
Enable log_checkpoints to log each checkpoint in the PostgreSQL server log. This provides useful diagnostic information for performance tuning and security investigations.
An improperly configured value for Server Parameter log_checkpoints could weaken security controls or allow unintended behavior. Setting this to ON for PostgreSQL ensures the Azure cloud platform operates within a well-defined security boundary.
az postgres flexible-server parameter show --resource-group <rg> \ --server-name <server> --name log_checkpoints --query 'value' # Should be "ON"
az postgres flexible-server parameter set --resource-group <rg> \ --server-name <server> --name log_checkpoints --value ON
5 — Logging and Monitoring
▶Azure diagnostic settings, activity log configuration, and alert policies for security monitoring.
5.1 Diagnostic Settings
▶Configure diagnostic settings for the subscription to capture all activity log categories: Administrative, Security, ServiceHealth, Alert, Recommendation, Policy, Autoscale, and ResourceHealth.
Failure to diagnostic Settings Capture All Activity Log Categories may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az monitor diagnostic-settings subscription list \
--query '[].logs[].{Category:category, Enabled:enabled}' -o tableNavigate to Monitor > Activity log > Export Activity Logs and create a diagnostic setting that sends all categories to a Log Analytics workspace or storage account.
5.2 Activity Log Alerts
▶Create an activity log alert to fire when a Network Security Group is created or updated. This detects unauthorized network configuration changes.
Failure to activity Log Alert Exists for Create/Update Network Security Group may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az monitor activity-log alert list --query "[?condition.allOf[?field=='operationName' && equals=='Microsoft.Network/networkSecurityGroups/write']]"
az monitor activity-log alert create -n "NSG-Create-Update" -g <rg> \
--condition category=Administrative \
and operationName=Microsoft.Network/networkSecurityGroups/write \
--action-group <actionGroupId>Create activity log alerts for security policy changes to detect when Azure Policy assignments are created, modified, or deleted.
Failure to activity Log Alert Exists for Create/Update/Delete Security Policy may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az monitor activity-log alert list \ --query "[?condition.allOf[?field=='operationName' && equals=='Microsoft.Authorization/policyAssignments/write']]"
Create activity log alerts for Microsoft.Authorization/policyAssignments/write and Microsoft.Authorization/policyAssignments/delete operations.
6 — Networking
▶Network security configuration including Network Security Groups, Network Watcher, and public IP management.
6.1 Network Security Groups
▶Ensure no Network Security Group allows unrestricted inbound SSH access (port 22) from the internet (0.0.0.0/0 or Any). SSH access should be restricted to specific IP ranges or through Azure Bastion.
Failure to no NSG Allows Inbound from 0.0.0.0/0 to Port 22 may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az network nsg list --query '[].{Name:name, RG:resourceGroup}' -o table
# Then for each NSG:
az network nsg rule list -g <rg> --nsg-name <nsg> \
--query "[?destinationPortRange=='22' && sourceAddressPrefix=='*' && access=='Allow' && direction=='Inbound']"Restrict SSH rules to specific source IP addresses or CIDR ranges. Consider using Azure Bastion for SSH access to eliminate public SSH exposure entirely.
Ensure no NSG allows unrestricted inbound RDP access (port 3389) from the internet. RDP is a frequent target of brute force attacks and should be restricted or replaced by Azure Bastion.
Failure to no NSG Allows Inbound from 0.0.0.0/0 to Port 3389 may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az network nsg rule list -g <rg> --nsg-name <nsg> \ --query "[?destinationPortRange=='3389' && sourceAddressPrefix=='*' && access=='Allow' && direction=='Inbound']"
Remove or restrict RDP rules. Use Azure Bastion or JIT VM access for remote management.
6.2 Network Watcher
▶Network Watcher provides network diagnostic and visualization tools. It should be enabled for every Azure region where network resources are deployed.
Failure to network Watcher is Enabled for All Regions in Use may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az network watcher list --query '[].{Location:location, State:provisioningState}' -o tableaz network watcher configure --resource-group NetworkWatcherRG \ --locations <region> --enabled true
Enable NSG flow logs for all Network Security Groups and configure traffic analytics with a Log Analytics workspace. Flow logs provide visibility into network traffic patterns for security analysis.
Failure to nSG Flow Logs are Enabled and Sent to Log Analytics may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az network watcher flow-log list --location <region> \
--query '[].{NSG:targetResourceId, Enabled:enabled, Analytics:flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled}'az network watcher flow-log create --location <region> --name <name> \ --nsg <nsgId> --storage-account <storageId> --enabled true \ --log-version 2 --retention 90 \ --traffic-analytics true --workspace <workspaceId>
7 — Virtual Machines
▶7.1 OS & Disk Encryption
▶Ensure all VM disks are managed disks rather than unmanaged (VHD). Managed disks provide built-in encryption, higher reliability, and better security integration.
Failure to virtual Machines Utilize Managed Disks may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az vm list --query '[?storageProfile.osDisk.managedDisk==null].{Name:name, RG:resourceGroup}' -o table
# Should return empty (no VMs with unmanaged disks)Migrate VMs from unmanaged to managed disks using az vm convert.
Use customer-managed keys (CMK) stored in Azure Key Vault for disk encryption. This provides full control over the encryption keys and enables key rotation and revocation.
Without encryption, OS and Data Disks may transmit or store sensitive information in cleartext, exposing it to interception, eavesdropping, or tampering. Encryption is a critical control for data confidentiality and integrity.
az vm encryption show --resource-group <rg> --name <vm> \
--query '{OSDisk:disks[0].statuses[0].code, DataDisks:disks[1:]}'Enable Azure Disk Encryption with a CMK from Key Vault, or use disk encryption sets with customer-managed keys.
Review installed VM extensions and ensure only approved, necessary extensions are installed. Unnecessary extensions increase the attack surface.
Failure to only Approved VM Extensions are Installed may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az vm extension list --resource-group <rg> --vm-name <vm> \
--query '[].{Name:name, Publisher:publisher, Type:typePropertiesType}' -o tableRemove unnecessary extensions: az vm extension delete -g <rg> --vm-name <vm> -n <extension>
8 — Key Vault
▶8.1 Key & Secret Management
▶Ensure soft delete and purge protection are enabled on all Key Vaults. Soft delete retains deleted vaults/secrets for a retention period. Purge protection prevents permanent deletion during the retention period.
Failure to key Vault is Recoverable (Soft Delete + Purge Protection) may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az keyvault list --query '[].{Name:name, SoftDelete:properties.enableSoftDelete, PurgeProtection:properties.enablePurgeProtection}' -o table
# Both should be trueaz keyvault update --name <vault> --enable-soft-delete true --enable-purge-protection true
Configure Key Vaults to use Azure RBAC for access control instead of vault access policies. RBAC provides more granular permissions and integrates with Azure's unified access management.
Failure to key Vault Uses RBAC Instead of Access Policies may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az keyvault list --query '[].{Name:name, RBAC:properties.enableRbacAuthorization}' -o table
# Should be true for all vaultsaz keyvault update --name <vault> --enable-rbac-authorization true
All keys stored in Key Vault should have an expiration date configured to enforce key rotation and prevent indefinite use of cryptographic keys.
Failure to key Vault Keys Have an Expiration Date Set may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az keyvault key list --vault-name <vault> \
--query '[].{Name:name, Expires:attributes.expires, Enabled:attributes.enabled}' -o tableaz keyvault key set-attributes --vault-name <vault> --name <key> \ --expires '2025-12-31T23:59:59Z'
9 — AppService
▶9.1 Authentication & TLS
▶Enable App Service Authentication (EasyAuth) for web apps that require authentication. This built-in feature handles authentication without requiring code changes.
Failure to app Service Authentication is Set on Azure App Service may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az webapp auth show --resource-group <rg> --name <app> --query 'enabled' # Should be true
az webapp auth update --resource-group <rg> --name <app> --enabled true \ --action LoginWithAzureActiveDirectory
Enable HTTPS-only mode on web applications to redirect all HTTP traffic to HTTPS, ensuring all data in transit is encrypted.
Failure to web App Redirects All HTTP Traffic to HTTPS may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az webapp show --resource-group <rg> --name <app> --query 'httpsOnly' # Should be true
az webapp update --resource-group <rg> --name <app> --set httpsOnly=true
Set the minimum TLS version for web apps to 1.2 or higher to protect against known vulnerabilities in TLS 1.0 and 1.1.
Failure to web App Uses the Latest TLS Version may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az webapp config show --resource-group <rg> --name <app> --query 'minTlsVersion' # Should be "1.2" or "1.3"
az webapp config set --resource-group <rg> --name <app> --min-tls-version 1.2
Use managed identities for web apps instead of storing credentials in app settings. Managed identities eliminate the need for developers to manage credentials and provide automatic token management.
Failure to web App Uses Managed Identity may leave the Azure cloud platform vulnerable to attack or non-compliant with organizational security policies. This control helps establish a consistent, hardened configuration baseline.
az webapp identity show --resource-group <rg> --name <app> --query 'type' # Should be "SystemAssigned" or "SystemAssigned, UserAssigned"
az webapp identity assign --resource-group <rg> --name <app>