Azure Security Best Practices

This page is a concrete checklist for teams setting up a new Azure environment. Each item names the specific Azure resource or setting involved, explains why it matters, and includes the CLI command or portal path to verify it. Use it to audit an existing environment or as a setup guide for a new one.

Identity: who can authenticate

1. Use managed identities for all application-to-Azure authentication

Every workload that needs to call an Azure service — reading from storage, connecting to Key Vault, calling a database — should authenticate using a managed identity, not a service principal with a password or client secret. Managed identities have credentials managed entirely by Azure: no password to store, rotate, or leak.

Check: Are any of your application service principals using a client secret older than 90 days? They should be replaced with managed identities where possible.

# List all app registrations with credentials (client secrets or certificates)
az ad app list --query "[].{name:displayName, appId:appId}" --output table

# Check expiry of credentials on a specific app
az ad app credential list \
  --id YOUR_APP_ID \
  --query "[].{type:type, endDate:endDateTime}" \
  --output table

See Managed Identities Overview for how to enable and assign managed identities.

2. Enable MFA for all human accounts in Microsoft Entra ID

A stolen password is the single most common entry point for Azure breaches. Multi-factor authentication stops password-only attacks. In Microsoft Entra ID, enable Security Defaults (which enforces MFA for all users) or configure Conditional Access policies for more granular control.

# Check if Security Defaults are enabled (returns true/false)
az rest \
  --method GET \
  --url https://graph.microsoft.com/v1.0/policies/identitySecurityDefaultsEnforcementPolicy \
  --query isEnabled

Security Defaults is the minimum baseline. For production environments with sensitive data, configure Conditional Access to require MFA for all sign-ins, block access from high-risk sign-in locations, and require compliant devices for privileged access.

3. Never share credentials between services or people

A shared service principal that multiple applications use means a compromised credential affects all of them. A shared user account that multiple team members use means you cannot audit who did what. Every principal should be dedicated: one identity per application, one user account per person.

4. Use service principals with certificates, not client secrets, when managed identities are not possible

When a workload truly cannot use a managed identity (for example, a script running outside Azure, or a CI/CD pipeline that needs to authenticate to Azure), prefer a certificate-based service principal over a client secret. Certificates can be rotated without changing the service principal, have a limited validity period, and cannot be extracted from a secure store the same way a string secret can. Store the certificate in Azure Key Vault.

# Create a service principal with a self-signed certificate (valid 1 year)
az ad sp create-for-rbac \
  --name my-pipeline-sp \
  --create-cert \
  --cert-output-path ./sp-cert.pem \
  --years 1

Access control: what each identity can do

5. Assign roles at the smallest possible scope

The principle of least privilege means giving each identity only the permissions it needs for its specific task. In Azure RBAC, this means scoping role assignments to the resource or resource group, not to the subscription.

An application that only needs to read from one storage account should have Storage Blob Data Reader on that storage account — not on the resource group, and certainly not Contributor on the subscription.

# List all role assignments at subscription scope (these should be minimal)
az role assignment list \
  --scope /subscriptions/YOUR_SUB_ID \
  --output table

# Count them — more than a handful warrants a review
az role assignment list \
  --scope /subscriptions/YOUR_SUB_ID \
  --query "length(@)"

6. Nobody should have Owner at subscription scope in normal operations

Owner on a subscription grants complete control over all resources and the ability to grant access to others. It is a break-glass permission for emergency situations, not a working permission. Regular administrative work should use Contributor (can manage resources, cannot change access) at the subscription level, or specific roles at the resource level. Audit subscription-level Owners regularly and reduce them to the minimum necessary.

# List all Owner role assignments at subscription scope
az role assignment list \
  --scope /subscriptions/YOUR_SUB_ID \
  --role Owner \
  --query "[].{principal:principalName, type:principalType}" \
  --output table

7. Review role assignments when people leave or change teams

Role assignments in Azure do not expire automatically. When someone leaves the organisation or changes projects, their old access remains unless you explicitly remove it. Use Microsoft Entra ID access reviews to schedule periodic reviews of group memberships and role assignments. At minimum, run a quarterly manual review of who has access to production subscriptions.

# List all role assignments for a specific user (useful during offboarding)
az role assignment list \
  --assignee user@example.com \
  --all \
  --output table

8. Use built-in roles before creating custom roles

Azure has over 100 built-in roles that cover the vast majority of use cases. Custom roles are harder to maintain, are not visible to new team members who do not know to look for them, and can be accidentally over-permissive. Check the built-in role list before creating a custom one. The most commonly used built-in roles for application identities are: Storage Blob Data Reader, Storage Blob Data Contributor, Key Vault Secrets User, and Service Bus Data Sender/Receiver.

Network: what can reach your services

9. Disable public access on storage accounts that do not need it

A storage account with public access enabled allows anyone on the internet to attempt to read its contents. Even if containers are not marked as public, having the setting enabled creates an unnecessary attack surface. The Microsoft Defender for Cloud recommendation “Storage accounts should prevent public access” will flag this.

# Disable public blob access on a storage account
az storage account update \
  --name mystorageaccount \
  --resource-group my-rg \
  --allow-blob-public-access false

# Check current setting across all accounts in a resource group
az storage account list \
  --resource-group my-rg \
  --query "[].{name:name, publicAccess:allowBlobPublicAccess}" \
  --output table

10. Use private endpoints for sensitive services

Private endpoints give a storage account, Key Vault, SQL database, or other service a private IP address in your virtual network. Traffic to the service stays within Azure’s network rather than crossing the public internet, and you can configure the service to reject all connections except those from the private endpoint.

Priority order for private endpoints: Key Vault (always), storage accounts containing sensitive data, Azure SQL and Cosmos DB databases in production, Azure Cache for Redis in production.

# Verify a storage account is rejecting public network access
az storage account show \
  --name mystorageaccount \
  --resource-group my-rg \
  --query networkRuleSet.defaultAction
# Should return "Deny" if configured to private-only access

11. Restrict inbound ports on VMs to what is actually needed

Virtual machine Network Security Groups (NSGs) should not allow SSH (port 22) or RDP (port 3389) from the internet (0.0.0.0/0). Use Azure Bastion for administrative access to VMs, or restrict SSH/RDP to specific known IP ranges. The Defender for Cloud recommendation “Management ports of virtual machines should be protected with just-in-time network access control” flags VMs with open management ports.

# Check NSG rules for a specific NSG
az network nsg rule list \
  --nsg-name my-nsg \
  --resource-group my-rg \
  --query "[?access=='Allow' && direction=='Inbound'].{name:name, port:destinationPortRange, source:sourceAddressPrefix}" \
  --output table

12. Restrict Azure service endpoints or use private endpoints for PaaS services accessed from VMs

If a VM needs to access a storage account or database, use service endpoints or private endpoints to ensure that traffic stays within the Azure network and the storage account accepts connections only from your virtual network, not from the public internet.

Secrets and encryption: protecting sensitive values and data

13. Store all credentials in Azure Key Vault

No connection strings, API keys, or passwords in application configuration files, environment variables set at deployment time, container image layers, or source code. Every secret goes into Azure Key Vault and is read at runtime via a managed identity or a Key Vault reference in App Service.

Verify: search your repositories for patterns like Server=, Password=, api_key=. Any of these in a config file or source file is a finding.

14. Set expiry dates on all secrets and rotate them

Secrets without expiry dates never expire. Set expiry dates when you create secrets in Key Vault and set up Event Grid notifications or rotation functions to handle rotation before the expiry date. See Rotating Secrets Automatically for the two-version pattern that avoids downtime during rotation.

# List secrets without expiry dates in a vault
az keyvault secret list \
  --vault-name my-vault \
  --query "[?attributes.expires == null].{name:name}" \
  --output table

15. Enable soft-delete and purge protection on all Key Vaults

Soft-delete is on by default for new vaults. Purge protection must be explicitly enabled. Enable it on any vault that stores secrets your applications depend on, or keys used for encryption (CMKs). Without purge protection, a deleted vault can be permanently destroyed before anyone notices.

# Check purge protection status on all vaults in a resource group
az keyvault list \
  --resource-group my-rg \
  --query "[].{name:name, softDelete:properties.enableSoftDelete, purgeProtection:properties.enablePurgeProtection}" \
  --output table

# Enable purge protection on an existing vault
az keyvault update \
  --name my-vault \
  --resource-group my-rg \
  --enable-purge-protection true

16. Verify encryption settings meet your compliance requirements

All Azure services encrypt data at rest by default. If your compliance framework requires customer-managed keys or double encryption, verify those settings are configured. See Encryption in Azure and Customer Managed Keys for guidance on when these are needed and what they involve.

# Verify storage account encryption settings
az storage account show \
  --name mystorageaccount \
  --resource-group my-rg \
  --query encryption

Monitoring: knowing what is happening

17. Enable diagnostic settings and send logs to a Log Analytics Workspace

Azure resource logs are not retained unless you explicitly configure diagnostic settings to send them somewhere. Create a Log Analytics Workspace and configure diagnostic settings on your critical resources (Key Vault, storage accounts, SQL databases, Azure AD) to forward logs there. Azure Activity Logs capture management-plane operations (who created, modified, or deleted resources); resource-specific logs capture data-plane operations (who read a secret, who queried a database).

# Create a Log Analytics Workspace
az monitor log-analytics workspace create \
  --resource-group my-rg \
  --workspace-name my-log-workspace \
  --location eastus

# Enable diagnostic settings on a Key Vault to send logs to the workspace
WORKSPACE_ID=$(az monitor log-analytics workspace show \
  --resource-group my-rg \
  --workspace-name my-log-workspace \
  --query id \
  --output tsv)

VAULT_ID=$(az keyvault show \
  --name my-vault \
  --resource-group my-rg \
  --query id \
  --output tsv)

az monitor diagnostic-settings create \
  --name vault-to-workspace \
  --resource $VAULT_ID \
  --workspace $WORKSPACE_ID \
  --logs '[{"category":"AuditEvent","enabled":true}]'

18. Open Microsoft Defender for Cloud and address the top 5 recommendations

Defender for Cloud is already assessing your subscription — it just needs to be opened. Navigate to Microsoft Defender for Cloud → Recommendations, sort by severity (High first), and address the top five findings. In a new environment, these commonly include: storage accounts with public access enabled, VMs with management ports open, missing MFA, SQL databases without audit logging, and resources missing diagnostic settings.

See Microsoft Defender for Cloud for a walkthrough of reading the Secure Score and fixing common findings.

19. Set up alerts for high-severity security events

Defender for Cloud can send security alerts to email or to an action group (which can trigger logic apps, function apps, or send to teams channels). Configure alerts for at least High and Critical severity findings so that someone is notified when a new serious security issue is detected.

# Create an email action group for security alerts
az monitor action-group create \
  --resource-group my-rg \
  --name security-alerts-group \
  --short-name sec-alerts \
  --email-receivers name="Security Team" email="security@example.com"

20. Enable Azure Activity Log retention for at least 90 days

By default, Azure Activity Logs are retained for 90 days. If you need longer retention for compliance reasons, configure a diagnostic setting to archive them to a storage account or send them to your Log Analytics Workspace (where you control the retention period). A 90-day retention period means that for any security investigation, you have at most 90 days of management operation history available.

Governance: structure that prevents drift

21. Tag all resources with environment, owner, and application

Resources without tags cannot be easily audited. A Key Vault with no tags looks identical to a test vault someone created and forgot. Tag every production resource with at minimum: environment: prod, owner: team-name, and application: app-name. Use resource tagging and consider an Azure Policy that requires tags on resource creation.

22. Use Azure Policy to enforce security guardrails

Azure Policy can deny the creation of resources that violate your security requirements. Common policies for security: deny storage accounts with public access enabled, deny resources created outside approved regions, require HTTPS on storage accounts, require secure transfer on storage accounts. Assign the Azure Security Benchmark initiative to your subscription to get a comprehensive set of policy-based controls.

23. Use resource locks on critical infrastructure

Apply CanNotDelete locks on Key Vaults (especially those holding CMKs), production databases, and resources whose deletion would cause a significant incident. This prevents accidental deletion by any principal — including Owners and administrators — without explicitly removing the lock first.

# Apply a delete lock to a Key Vault
az lock create \
  --name protect-prod-vault \
  --resource-group my-rg \
  --resource-name my-vault \
  --resource-type Microsoft.KeyVault/vaults \
  --lock-type CanNotDelete

24. Separate production from non-production into distinct subscriptions

Keeping development, staging, and production in the same subscription means a misconfigured access policy or an incorrect role assignment in development can affect production. Separate subscriptions create an access control boundary: a developer with Contributor on the dev subscription has no access to the production subscription unless explicitly granted. This also gives you clean billing separation and makes it easier to apply different Azure Policy sets per environment.

The most common security failures in Azure

  1. Service principals with long-lived client secrets shared across applications. One leaked secret compromises every application using it. Replace with managed identities where possible; use separate service principals with short-lived secrets or certificates where not.
  2. Subscription Owner granted to developers for convenience. Owner lets someone grant themselves or anyone else any permission on any resource. “Just for now while we set things up” becomes permanent. Set up proper role assignments at the right scope from the start.
  3. Production secrets in CI/CD pipeline variables. Pipeline variables are visible to anyone with access to the pipeline, are often logged, and are copied into deployment artifacts. Use managed identities to authenticate pipelines to Azure and Key Vault references to inject secrets at runtime.
  4. No logging until an incident. When a security incident occurs in an environment with no diagnostic settings, you have no log data to investigate. Configure logging before you need it, because you cannot retroactively get logs from before diagnostic settings were enabled.
  5. Network-isolated services that are actually public. Teams add a Key Vault or SQL database, tick “enable private endpoint”, but forget to also set the network default action to Deny. The private endpoint exists but the public endpoint is also still accepting connections. Always verify that the public endpoint is disabled, not just that the private endpoint is enabled.

Frequently asked questions

What should a team do first when setting up a new Azure environment?

Start with identity and access: assign roles at the resource group or resource level rather than the subscription level, require MFA for all human accounts, and ensure no application is using a password-based service principal where a managed identity would work. These three steps prevent the most common and most damaging security failures in Azure.

How often should we review our Azure security posture?

At minimum: check your Microsoft Defender for Cloud Secure Score monthly and address any newly surfaced High severity recommendations. Review role assignments quarterly — people change teams and projects, and accumulated permissions grow over time. Review network access controls whenever you add a new service. Run a full security review of a new workload before it goes to production.

We are a small team — do all of these practices apply to us?

The identity and access items (managed identities, no shared credentials, least-privilege roles) apply regardless of team size because the cost of implementation is low and the blast radius of getting them wrong is high. The network isolation items (private endpoints) matter most for services handling sensitive data. The monitoring items matter when you are running workloads 24/7 in production. Smaller teams can deprioritise double encryption and complex CMK setups unless a compliance framework specifically requires them.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.