Microsoft Azureintermediate

Azure Storage Encryption Guide: Protecting Data at Rest

Learn how to encrypt Azure data at rest using Azure Storage encryption, managed disk encryption, Azure SQL TDE, and customer-managed keys in Key Vault for enterprise compliance.

16 min readUpdated 2026-01-13

Encrypting data at rest is a fundamental security control that protects your information from unauthorized access even if physical storage media is compromised. Azure provides multiple encryption options across storage accounts, managed disks, and databases. This guide covers implementing comprehensive encryption across your Azure environment.

This article is part of our comprehensive cloud security tips guide, focusing specifically on Azure data encryption best practices.

Overview

Azure provides several encryption mechanisms for data at rest:

  • Azure Storage Service Encryption (SSE): Automatic encryption for blob, file, table, and queue storage
  • Azure Disk Encryption: Encrypts OS and data disks for VMs using BitLocker (Windows) or DM-Crypt (Linux)
  • Server-Side Encryption (SSE) for Managed Disks: Platform-managed or customer-managed key encryption
  • Transparent Data Encryption (TDE): Automatic encryption for Azure SQL Database and Synapse
  • Azure Key Vault: Secure key management for customer-managed keys

Prerequisites

Before implementing encryption, ensure you have:

  • Azure subscription with Contributor or higher access
  • Azure Key Vault for customer-managed keys (Key Vault Premium for HSM-backed keys)
  • Azure CLI (2.50.0+) or Azure PowerShell module (10.0.0+)
  • Understanding of encryption concepts and key management
  • Compliance requirements documentation (HIPAA, PCI-DSS, SOC 2, etc.)

Part 1: Azure Storage Encryption

Default Encryption (Microsoft-Managed Keys)

All Azure Storage accounts are automatically encrypted with Microsoft-managed keys:

# Verify encryption is enabled (it always is)
az storage account show \
  --name mystorageaccount \
  --resource-group rg-security \
  --query "encryption.services.blob.enabled"
# Returns: true

Enable Infrastructure Encryption (Double Encryption)

For sensitive workloads requiring defense-in-depth:

Using Azure Portal

  1. Navigate to your Storage Account
  2. Go to Settings > Encryption
  3. Under Infrastructure encryption, select Enabled

Note: Infrastructure encryption can only be enabled during storage account creation.

Using Azure CLI

# Create storage account with infrastructure encryption
az storage account create \
  --name securestorageaccount \
  --resource-group rg-security \
  --location eastus \
  --sku Standard_GRS \
  --kind StorageV2 \
  --require-infrastructure-encryption true \
  --min-tls-version TLS1_2 \
  --allow-blob-public-access false

# Verify infrastructure encryption
az storage account show \
  --name securestorageaccount \
  --resource-group rg-security \
  --query "encryption.requireInfrastructureEncryption"
# Returns: true

Configure Customer-Managed Keys (CMK)

For organizations requiring key custody and control:

Step 1: Create Key Vault

# Create Key Vault with required protections
az keyvault create \
  --name kv-storage-encryption \
  --resource-group rg-security \
  --location eastus \
  --sku premium \
  --enable-soft-delete true \
  --retention-days 90 \
  --enable-purge-protection true

# Note: Purge protection cannot be disabled once enabled

Step 2: Create Encryption Key

# Create RSA key for storage encryption
az keyvault key create \
  --vault-name kv-storage-encryption \
  --name storage-cmk-key \
  --kty RSA \
  --size 2048 \
  --ops wrapKey unwrapKey

# Get key URI for later use
KEY_URI=$(az keyvault key show \
  --vault-name kv-storage-encryption \
  --name storage-cmk-key \
  --query key.kid -o tsv)

echo "Key URI: $KEY_URI"

Step 3: Enable System-Assigned Identity on Storage Account

# Enable managed identity
az storage account update \
  --name securestorageaccount \
  --resource-group rg-security \
  --assign-identity

# Get the principal ID
STORAGE_PRINCIPAL=$(az storage account show \
  --name securestorageaccount \
  --resource-group rg-security \
  --query identity.principalId -o tsv)

echo "Storage Identity: $STORAGE_PRINCIPAL"

Step 4: Grant Key Vault Access

# Grant storage account access to Key Vault
az keyvault set-policy \
  --name kv-storage-encryption \
  --object-id $STORAGE_PRINCIPAL \
  --key-permissions get wrapKey unwrapKey

# Alternatively, use RBAC (recommended)
KEYVAULT_ID=$(az keyvault show \
  --name kv-storage-encryption \
  --query id -o tsv)

az role assignment create \
  --role "Key Vault Crypto Service Encryption User" \
  --assignee-object-id $STORAGE_PRINCIPAL \
  --assignee-principal-type ServicePrincipal \
  --scope $KEYVAULT_ID

Step 5: Configure Storage Account for CMK

# Enable customer-managed keys
az storage account update \
  --name securestorageaccount \
  --resource-group rg-security \
  --encryption-key-source Microsoft.Keyvault \
  --encryption-key-vault $(az keyvault show --name kv-storage-encryption --query properties.vaultUri -o tsv) \
  --encryption-key-name storage-cmk-key

# Verify CMK configuration
az storage account show \
  --name securestorageaccount \
  --resource-group rg-security \
  --query "encryption.keySource"
# Returns: "Microsoft.Keyvault"

Part 2: Managed Disk Encryption

Azure managed disks support multiple encryption options.

Server-Side Encryption with Platform-Managed Keys

This is the default and requires no configuration:

# Create a standard encrypted managed disk
az disk create \
  --name disk-encrypted-pmk \
  --resource-group rg-security \
  --location eastus \
  --size-gb 128 \
  --sku Premium_LRS

# Verify encryption
az disk show \
  --name disk-encrypted-pmk \
  --resource-group rg-security \
  --query "encryption.type"
# Returns: "EncryptionAtRestWithPlatformKey"

Server-Side Encryption with Customer-Managed Keys

Step 1: Create Disk Encryption Set

# Create encryption key for disks
az keyvault key create \
  --vault-name kv-storage-encryption \
  --name disk-cmk-key \
  --kty RSA \
  --size 2048

# Create Disk Encryption Set
az disk-encryption-set create \
  --name des-customer-managed \
  --resource-group rg-security \
  --location eastus \
  --source-vault kv-storage-encryption \
  --key-url $(az keyvault key show \
    --vault-name kv-storage-encryption \
    --name disk-cmk-key \
    --query key.kid -o tsv) \
  --encryption-type EncryptionAtRestWithCustomerKey

# Get Disk Encryption Set identity
DES_PRINCIPAL=$(az disk-encryption-set show \
  --name des-customer-managed \
  --resource-group rg-security \
  --query identity.principalId -o tsv)

Step 2: Grant Key Vault Access

# Grant Disk Encryption Set access to Key Vault
az keyvault set-policy \
  --name kv-storage-encryption \
  --object-id $DES_PRINCIPAL \
  --key-permissions get wrapKey unwrapKey

# Or use RBAC
az role assignment create \
  --role "Key Vault Crypto Service Encryption User" \
  --assignee-object-id $DES_PRINCIPAL \
  --assignee-principal-type ServicePrincipal \
  --scope $KEYVAULT_ID

Step 3: Create Disk with CMK

# Get Disk Encryption Set ID
DES_ID=$(az disk-encryption-set show \
  --name des-customer-managed \
  --resource-group rg-security \
  --query id -o tsv)

# Create disk with customer-managed keys
az disk create \
  --name disk-encrypted-cmk \
  --resource-group rg-security \
  --location eastus \
  --size-gb 128 \
  --sku Premium_LRS \
  --encryption-type EncryptionAtRestWithCustomerKey \
  --disk-encryption-set $DES_ID

# Verify encryption type
az disk show \
  --name disk-encrypted-cmk \
  --resource-group rg-security \
  --query "encryption"

Enable Double Encryption for Disks

For maximum security, combine platform and customer keys:

# Create Disk Encryption Set with double encryption
az disk-encryption-set create \
  --name des-double-encryption \
  --resource-group rg-security \
  --location eastus \
  --source-vault kv-storage-encryption \
  --key-url $(az keyvault key show \
    --vault-name kv-storage-encryption \
    --name disk-cmk-key \
    --query key.kid -o tsv) \
  --encryption-type EncryptionAtRestWithPlatformAndCustomerKeys

# Create disk with double encryption
az disk create \
  --name disk-double-encrypted \
  --resource-group rg-security \
  --location eastus \
  --size-gb 128 \
  --sku Premium_LRS \
  --encryption-type EncryptionAtRestWithPlatformAndCustomerKeys \
  --disk-encryption-set $(az disk-encryption-set show \
    --name des-double-encryption \
    --resource-group rg-security \
    --query id -o tsv)

Part 3: Azure SQL Transparent Data Encryption (TDE)

Azure SQL Database and Synapse Analytics automatically encrypt data with TDE.

Verify TDE Status

# Check TDE status for Azure SQL Database
az sql db tde show \
  --database mydb \
  --server mysqlserver \
  --resource-group rg-security

Configure Customer-Managed TDE

Step 1: Prepare Key Vault

# Create key for SQL TDE
az keyvault key create \
  --vault-name kv-storage-encryption \
  --name sql-tde-key \
  --kty RSA \
  --size 2048

Step 2: Configure SQL Server Identity

# Enable managed identity for SQL Server
az sql server update \
  --name mysqlserver \
  --resource-group rg-security \
  --assign-identity

# Get SQL Server identity
SQL_PRINCIPAL=$(az sql server show \
  --name mysqlserver \
  --resource-group rg-security \
  --query identity.principalId -o tsv)

# Grant Key Vault access
az keyvault set-policy \
  --name kv-storage-encryption \
  --object-id $SQL_PRINCIPAL \
  --key-permissions get wrapKey unwrapKey

Step 3: Set TDE Protector

# Get Key Vault key ID
TDE_KEY_ID=$(az keyvault key show \
  --vault-name kv-storage-encryption \
  --name sql-tde-key \
  --query key.kid -o tsv)

# Set as TDE protector
az sql server tde-key set \
  --server-key-type AzureKeyVault \
  --kid $TDE_KEY_ID \
  --server mysqlserver \
  --resource-group rg-security

# Verify TDE protector
az sql server tde-key show \
  --server mysqlserver \
  --resource-group rg-security

Part 4: Key Rotation

Regular key rotation is essential for security and compliance.

Rotate Storage Account Keys

# Rotate primary key
az storage account keys renew \
  --name securestorageaccount \
  --resource-group rg-security \
  --key primary

# Rotate secondary key
az storage account keys renew \
  --name securestorageaccount \
  --resource-group rg-security \
  --key secondary

Rotate Customer-Managed Keys

# Create new key version
az keyvault key create \
  --vault-name kv-storage-encryption \
  --name storage-cmk-key \
  --kty RSA \
  --size 2048

# Storage account automatically uses latest key version
# Verify the new key is in use
az storage account show \
  --name securestorageaccount \
  --resource-group rg-security \
  --query "encryption.keyVaultProperties.currentVersionedKeyIdentifier"

Automate Key Rotation

# Enable automatic key rotation in Key Vault (Preview)
az keyvault key rotation-policy update \
  --vault-name kv-storage-encryption \
  --name storage-cmk-key \
  --value @rotation-policy.json

rotation-policy.json:

{
  "lifetimeActions": [
    {
      "trigger": {
        "timeAfterCreate": "P90D"
      },
      "action": {
        "type": "Rotate"
      }
    },
    {
      "trigger": {
        "timeBeforeExpiry": "P30D"
      },
      "action": {
        "type": "Notify"
      }
    }
  ],
  "attributes": {
    "expiryTime": "P1Y"
  }
}

Terraform Configuration

Implement encryption using infrastructure as code:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.85"
    }
  }
}

provider "azurerm" {
  features {
    key_vault {
      purge_soft_delete_on_destroy = false
    }
  }
}

# Key Vault for encryption keys
resource "azurerm_key_vault" "encryption" {
  name                       = "kv-encryption-${var.environment}"
  location                   = var.location
  resource_group_name        = var.resource_group_name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "premium"
  soft_delete_retention_days = 90
  purge_protection_enabled   = true

  enable_rbac_authorization = true
}

# Encryption key for storage
resource "azurerm_key_vault_key" "storage_cmk" {
  name         = "storage-cmk-key"
  key_vault_id = azurerm_key_vault.encryption.id
  key_type     = "RSA"
  key_size     = 2048

  key_opts = ["wrapKey", "unwrapKey"]

  rotation_policy {
    expire_after         = "P90D"
    notify_before_expiry = "P30D"

    automatic {
      time_after_creation = "P60D"
    }
  }
}

# Storage account with CMK encryption
resource "azurerm_storage_account" "secure" {
  name                            = "securestorageacct"
  resource_group_name             = var.resource_group_name
  location                        = var.location
  account_tier                    = "Standard"
  account_replication_type        = "GRS"
  min_tls_version                 = "TLS1_2"
  enable_https_traffic_only       = true
  allow_nested_items_to_be_public = false

  infrastructure_encryption_enabled = true

  identity {
    type = "SystemAssigned"
  }

  customer_managed_key {
    key_vault_key_id          = azurerm_key_vault_key.storage_cmk.id
    user_assigned_identity_id = null # Uses system-assigned identity
  }
}

# Grant storage account access to Key Vault
resource "azurerm_role_assignment" "storage_key_vault" {
  scope                = azurerm_key_vault.encryption.id
  role_definition_name = "Key Vault Crypto Service Encryption User"
  principal_id         = azurerm_storage_account.secure.identity[0].principal_id
}

# Disk Encryption Set
resource "azurerm_disk_encryption_set" "cmk" {
  name                = "des-customer-managed"
  location            = var.location
  resource_group_name = var.resource_group_name
  key_vault_key_id    = azurerm_key_vault_key.storage_cmk.id
  encryption_type     = "EncryptionAtRestWithCustomerKey"

  identity {
    type = "SystemAssigned"
  }
}

# Grant Disk Encryption Set access to Key Vault
resource "azurerm_role_assignment" "des_key_vault" {
  scope                = azurerm_key_vault.encryption.id
  role_definition_name = "Key Vault Crypto Service Encryption User"
  principal_id         = azurerm_disk_encryption_set.cmk.identity[0].principal_id
}

# Encrypted managed disk
resource "azurerm_managed_disk" "encrypted" {
  name                   = "disk-encrypted-cmk"
  location               = var.location
  resource_group_name    = var.resource_group_name
  storage_account_type   = "Premium_LRS"
  create_option          = "Empty"
  disk_size_gb           = 128
  disk_encryption_set_id = azurerm_disk_encryption_set.cmk.id
}

Monitoring and Compliance

Monitor Encryption Status

# Check all storage accounts for CMK
az storage account list \
  --query "[].{Name:name, KeySource:encryption.keySource, InfraEncrypt:encryption.requireInfrastructureEncryption}" \
  --output table

# Check all disks for encryption type
az disk list \
  --query "[].{Name:name, EncryptionType:encryption.type}" \
  --output table

Azure Policy for Encryption Compliance

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Storage/storageAccounts"
      },
      {
        "field": "Microsoft.Storage/storageAccounts/encryption.keySource",
        "notEquals": "Microsoft.Keyvault"
      }
    ]
  },
  "then": {
    "effect": "deny"
  }
}

Best Practices

  1. Always enable purge protection on Key Vaults storing encryption keys
  2. Use RBAC instead of access policies for Key Vault access control
  3. Implement automated key rotation with at least annual rotation
  4. Back up encryption keys to secure offline storage
  5. Use HSM-backed keys (Key Vault Premium) for highest security
  6. Monitor key access with diagnostic logs and alerts
  7. Test key recovery procedures before production deployment
  8. Document key dependencies to understand impact of key revocation

Troubleshooting

Issue: Storage Account Cannot Access Key Vault

# Verify managed identity exists
az storage account show \
  --name securestorageaccount \
  --resource-group rg-security \
  --query "identity.principalId"

# Check Key Vault access policies
az keyvault show \
  --name kv-storage-encryption \
  --query "properties.accessPolicies"

# Or check RBAC assignments
az role assignment list \
  --scope $(az keyvault show --name kv-storage-encryption --query id -o tsv)

Issue: Disk Encryption Set in Failed State

# Check Disk Encryption Set status
az disk-encryption-set show \
  --name des-customer-managed \
  --resource-group rg-security \
  --query "provisioningState"

# Verify key is accessible
az keyvault key show \
  --vault-name kv-storage-encryption \
  --name disk-cmk-key

Frequently Asked Questions

Find answers to common questions

Microsoft-managed keys (MMK) are automatically created, stored, and rotated by Microsoft—requiring no action from you. Customer-managed keys (CMK) are encryption keys you create and manage in Azure Key Vault, giving you full control over key rotation, access policies, and the ability to revoke access. CMK is recommended for organizations with strict compliance requirements (HIPAA, PCI-DSS) or those needing to prove key custody for audits.

Azure Infrastructure Experts

Comprehensive Azure management including architecture, migration, security, and 24/7 operations.