Skip to main content

Getting Started with Azure Key Vault

Key Vault is the first thing I configure in any new Azure environment. Before the first application gets deployed, before the first pipeline runs, there needs to be somewhere to put secrets that isn't a config file or an environment variable committed to a repo. Key Vault is that place.

Creating a vault

Creating a Key Vault

Using Azure CLI

# Create resource group
az group create --name rg-keyvault --location eastus

# Create Key Vault with soft delete and purge protection
az keyvault create \
--name kv-myapp-prod \
--resource-group rg-keyvault \
--location eastus \
--enable-soft-delete true \
--enable-purge-protection true \
--retention-days 90

Using Azure Portal

  1. Navigate to Key Vault in Azure Portal
  2. Click + Create
  3. Select subscription and resource group
  4. Enter unique vault name (3-24 characters, alphanumeric and hyphens)
  5. Choose region and pricing tier (Standard or Premium with HSM)
  6. Configure Access Configuration (Azure RBAC recommended over legacy access policies)
  7. Enable Soft delete (90-day retention recommended)
  8. Enable Purge protection for production vaults
  9. Review and create

Storing and Retrieving Secrets

# Store a secret
az keyvault secret set \
--vault-name kv-myapp-prod \
--name db-connection-string \
--value "Server=myserver;Database=mydb;User=admin;Password=P@ssw0rd"

# Retrieve a secret
az keyvault secret show \
--vault-name kv-myapp-prod \
--name db-connection-string \
--query value -o tsv

# List all secrets
az keyvault secret list --vault-name kv-myapp-prod -o table

Managing Encryption Keys

# Create an encryption key
az keyvault key create \
--vault-name kv-myapp-prod \
--name my-encryption-key \
--protection software \
--kty RSA \
--size 2048

# For HSM-protected keys (Premium tier only)
az keyvault key create \
--vault-name kv-myapp-prod \
--name my-hsm-key \
--protection hsm \
--kty RSA-HSM \
--size 4096

Terraform Example

# Create Key Vault
resource "azurerm_key_vault" "main" {
name = "kv-${var.project}-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "premium"

# Security features
soft_delete_retention_days = 90
purge_protection_enabled = true

# Network security
network_acls {
default_action = "Deny"
bypass = "AzureServices"
ip_rules = ["203.0.113.0/24"]
virtual_network_subnet_ids = [azurerm_subnet.private.id]
}

# Enable Azure RBAC for data plane
enable_rbac_authorization = true
}

# Store a secret
resource "azurerm_key_vault_secret" "db_password" {
name = "database-password"
value = random_password.db_password.result
key_vault_id = azurerm_key_vault.main.id
}

# Grant access using RBAC (recommended)
resource "azurerm_role_assignment" "secrets_user" {
scope = azurerm_key_vault.main.id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity.app.principal_id
}

CI/CD Integration

GitHub Actions

name: Deploy with Key Vault Secrets

on: [push]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Get secrets from Key Vault
uses: azure/get-keyvault-secrets@v1
with:
keyvault: "kv-myapp-prod"
secrets: 'db-connection-string, api-key, storage-account-key'
id: keyvault

- name: Use secrets in deployment
run: |
echo "Deploying with connection string"
# Secrets available as: ${{ steps.keyvault.outputs.db-connection-string }}

Azure DevOps

variables:
- group: KeyVaultSecrets # Variable group linked to Key Vault

steps:
- task: AzureKeyVault@2
inputs:
azureSubscription: 'Production'
KeyVaultName: 'kv-myapp-prod'
SecretsFilter: '*'
RunAsPreJob: true

Best Practices

Use Managed Identities for Access

I never store Key Vault credentials in application code or environment variables. I assign a Managed Identity to the application and grant Key Vault permissions to that identity.

# Assign system-assigned managed identity to VM
az vm identity assign \
--resource-group rg-app \
--name vm-app-01

# Grant Key Vault Secrets User role
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <managed-identity-principal-id> \
--scope /subscriptions/{sub-id}/resourceGroups/rg-keyvault/providers/Microsoft.KeyVault/vaults/kv-myapp-prod

Enable Soft Delete and Purge Protection

  • Soft Delete: Retains deleted vaults and secrets for 7-90 days (90 recommended)
  • Purge Protection: Prevents permanent deletion during retention period
  • I enable both for every production vault — I've never had a good reason not to

Use Azure RBAC Over Access Policies

  • Modern Approach: Azure RBAC provides centralized access management
  • Granular Control: Built-in roles like Key Vault Secrets User, Key Vault Crypto Officer
  • Consistency: Same access control model as other Azure resources

Implement Network Security

# Restrict access to specific networks
az keyvault network-rule add \
--name kv-myapp-prod \
--resource-group rg-keyvault \
--vnet-name vnet-prod \
--subnet subnet-app

# Set default action to deny
az keyvault update \
--name kv-myapp-prod \
--resource-group rg-keyvault \
--default-action Deny

Use Private Endpoints

I always disable public access on production vaults and use Private Link:

  • Secrets never traverse public internet
  • Integrated with VNet DNS resolution
  • Compliant with zero-trust security model

Secret Rotation Strategy

  • Automate Rotation: Use Key Vault's integrated rotation for supported services
  • Versioning: Key Vault maintains secret versions automatically
  • Monitoring: Set up alerts for expiring secrets and certificates

Things to Avoid

I never hardcode secrets in application code, even temporarily. I also never use legacy access policies for new deployments — RBAC is the right model and I enforce it consistently.

I avoid granting overly permissive access. Applications get the Key Vault Secrets User role, not Key Vault Administrator. I never disable soft delete and purge protection in production, and I never allow unrestricted network access on production vaults.

I don't put non-sensitive configuration data in Key Vault. That belongs in App Configuration. I also keep secrets separated by environment — sharing secrets between dev and prod is a compliance issue waiting to happen.

I use separate Key Vaults per environment, grant least privilege access with RBAC, enable diagnostic logging to Log Analytics, use managed identities for service-to-service authentication, set secret expiration dates and rotation schedules, and use the Premium tier with HSM for highly sensitive keys.

Monitoring and Logging

Enable Diagnostic Settings

# Send logs to Log Analytics
az monitor diagnostic-settings create \
--name KeyVaultLogs \
--resource /subscriptions/{sub-id}/resourceGroups/rg-keyvault/providers/Microsoft.KeyVault/vaults/kv-myapp-prod \
--logs '[{"category": "AuditEvent", "enabled": true}]' \
--metrics '[{"category": "AllMetrics", "enabled": true}]' \
--workspace /subscriptions/{sub-id}/resourceGroups/rg-monitoring/providers/Microsoft.OperationalInsights/workspaces/law-prod

Key Metrics to Monitor

  • Vault Availability: Target 99.9%+
  • Total API Hits: Monitor for unusual spikes
  • Failed Requests: Investigate authentication failures
  • Latency: Service API latency (P95, P99)

Set Up Alerts

# Alert on failed authentication attempts
az monitor metrics alert create \
--name FailedKeyVaultAuth \
--resource-group rg-keyvault \
--scopes /subscriptions/{sub-id}/resourceGroups/rg-keyvault/providers/Microsoft.KeyVault/vaults/kv-myapp-prod \
--condition "count ServiceApiResult == 401 > 10" \
--window-size 5m \
--evaluation-frequency 1m

Common Use Cases

  1. Application Secrets: Database connection strings, API keys
  2. Encryption Keys: For Azure Storage, Disk Encryption, Always Encrypted
  3. SSL/TLS Certificates: Automated provisioning and renewal
  4. DevOps Pipelines: Secure credential storage for CI/CD
  5. Bring Your Own Key (BYOK): Import your own encryption keys
  6. Signing Operations: Code signing, document signing