The Complete Azure Key Vault Tutorial(2025): Secrets, Keys, Certificates & DevOps Security Best Practices
Imagine storing passwords, API keys, and secrets in plain text inside your code—terrifying, right? I’ve seen this happen more times than I’d like to admit in my DevOps career. A developer pushes code to a public GitHub repo, and within minutes, someone’s scraped those database credentials. Game over.
That’s exactly what Azure Key Vault prevents.
In this guide, I’ll walk you through everything you need to know about Azure Key Vault from a DevOps perspective. Whether you’re preparing for your AZ-104, AZ-204, or AZ-500 certification, or you’re just tired of juggling secrets across environments, you’re in the right place.
We’ll cover the architecture, dive into practical CLI examples, explore CI/CD integrations, and discuss the security best practices I wish someone had taught me when I started. Think of this as your mentor sitting beside you, sharing real-world lessons learned from securing production workloads.
Let’s get started.
Table of Contents Azure Key Vault Tutorial
What is Azure Key Vault and Why Should You Care?
Azure Key Vault is Microsoft’s managed cloud service for securely storing and accessing secrets, cryptographic keys, and certificates. Think of it as a digital safe deposit box for your application’s most sensitive information.
Here’s the analogy I use with my team: You wouldn’t leave your house keys under the doormat, would you? Yet developers often “hide” credentials in environment variables, configuration files, or worse—directly in source code. Key Vault is like having a bank vault with biometric access, audit logs, and multiple layers of protection.
Why Key Vault Matters in Modern DevOps
In traditional setups, secrets management was a nightmare. You’d have database passwords scattered across configuration files, API keys hardcoded in scripts, and SSL certificates stored on developer laptops. Every deployment meant manually updating secrets across environments.
Azure Key Vault centralizes this chaos. It provides a single source of truth for all your sensitive data, with built-in access control, encryption, and audit logging. When your Azure Function needs a database password, it requests it from Key Vault at runtime—never storing it locally.
Real-World Use Cases I’ve Implemented
From my experience deploying hundreds of applications on Azure, here are the scenarios where Key Vault becomes indispensable:
Storing database connection strings for multi-tier applications without exposing them in app configuration files. Your web app retrieves the connection string directly from Key Vault when it starts up.
Managing SSL/TLS certificates across multiple App Services and Application Gateways. Key Vault automatically renews certificates and notifies you before expiration—no more 3 AM pages because a cert expired.
Integrating with GitHub Actions and Azure DevOps to securely inject secrets into CI/CD pipelines. Your deployment workflows pull secrets dynamically from Key Vault instead of storing them as pipeline variables.
Encryption key management for Azure Disk Encryption, Storage Account encryption, and SQL Transparent Data Encryption. Key Vault becomes your centralized key management service.
The bottom line? If your application handles any sensitive data—and let’s be honest, which one doesn’t—you need Key Vault in your architecture.
Azure Key Vault Architecture: Understanding the Foundation
Before we dive into implementation, let’s understand how Key Vault actually works under the hood. I’ve found that grasping the architecture makes everything else click into place.
Core Components of Key Vault
Azure Key Vault itself is the container—your secure vault. Within it, you can store three types of objects: Secrets, Keys, and Certificates. Each vault exists in a specific Azure region and has a unique DNS name (like https://myvault.vault.azure.net).
Secrets are any sensitive text-based data. Database passwords, API tokens, connection strings, or even entire JSON configuration files. They’re encrypted at rest and returned to your application only when properly authenticated.
Keys are cryptographic keys used for encryption operations. These can be RSA or EC (Elliptic Curve) keys, and you can use them to encrypt data, sign tokens, or secure other cryptographic operations. The beauty here is that the key material never leaves Key Vault—all operations happen inside.
Certificates are X.509 certificates with their associated private keys. Key Vault can generate self-signed certificates, integrate with Certificate Authorities like DigiCert or GlobalSign, and automatically handle renewals.
How Authentication and Encryption Work
Here’s where Key Vault gets interesting from a security perspective. All access to Key Vault is authenticated through Azure Active Directory (now Microsoft Entra ID). There are no usernames or passwords—only managed identities, service principals, or user accounts with proper Azure AD credentials.
When your application requests a secret, here’s what happens behind the scenes:
Your app presents an Azure AD token (obtained through managed identity or service principal authentication). Key Vault validates this token with Azure AD to confirm the identity. Key Vault checks whether that identity has permission to read the specific secret (via Access Policies or RBAC roles). If authorized, Key Vault decrypts the secret and returns it over an encrypted HTTPS connection.
The secret is encrypted at rest using Microsoft-managed keys by default. For organizations with compliance requirements, you can use customer-managed keys stored in Key Vault’s Managed HSM (Hardware Security Module) tier for added control.
Integration with Azure Services
Key Vault isn’t an isolated service—it’s deeply integrated into the Azure ecosystem. Azure App Service and Azure Functions can reference Key Vault secrets directly in their application settings. Azure Kubernetes Service can mount secrets as volumes or inject them as environment variables. Azure DevOps and GitHub Actions have native tasks for retrieving Key Vault secrets during pipeline execution.
I always tell my team: Key Vault is the central nervous system of your Azure security architecture. Everything that needs credentials or encryption keys connects to it.
Reflection: Think about your current application stack. How many places are you storing secrets right now? Configuration files? Environment variables? Pipeline variables? Key Vault can consolidate all of these.
Secrets, Keys, and Certificates: Choosing the Right Object Type
One of the first questions I get from teams new to Key Vault is: “Should I store this as a secret, key, or certificate?” Let’s break down each type and when to use them.
Secrets: Your Application’s Sensitive Text Data
Secrets are the workhorses of Key Vault. Any text-based sensitive information should be stored as a secret. This includes database passwords, API keys, OAuth client secrets, service account credentials, or even entire JSON configuration blocks.
Here’s a real example from a project I worked on: We had a Node.js API that needed to connect to MongoDB, call external APIs from three different vendors, and authenticate with SendGrid for emails. Instead of managing four different environment variables across development, staging, and production, we stored all of them as Key Vault secrets.
The code looked clean:
const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");
const vaultUrl = "https://myvault.vault.azure.net";
const client = new SecretClient(vaultUrl, new DefaultAzureCredential());
const mongoSecret = await client.getSecret("MongoConnectionString");
const sendgridSecret = await client.getSecret("SendGridApiKey");
Notice how we’re using DefaultAzureCredential? This automatically uses the managed identity when running in Azure (App Service, Functions, AKS) or falls back to Azure CLI credentials during local development. No hardcoded credentials anywhere.
Keys: Cryptographic Operations Without Exposing Key Material
Keys in Key Vault are for cryptographic operations where you need to encrypt, decrypt, sign, or verify data—but you don’t want the actual key material exposed to your application.
Think of it this way: With a secret, your application retrieves the value and can do whatever it wants with it. With a key, your application says “encrypt this data” and Key Vault performs the operation internally, never revealing the actual key.
I use this pattern for encrypting sensitive user data before storing it in databases. The application sends plaintext to Key Vault, gets back ciphertext, and stores that. On retrieval, it sends ciphertext to Key Vault and gets back plaintext. The encryption key never touches the application layer.
This approach is critical for compliance requirements like GDPR, HIPAA, or PCI-DSS where you need provable key management and audit trails.
Certificates: Managing TLS/SSL the DevOps Way
Certificates in Key Vault are specifically for X.509 certificates—primarily SSL/TLS certificates for securing web traffic. What makes this powerful is that Key Vault can automatically renew certificates from integrated CAs.
In a recent project, we had 12 App Services across three environments, each needing custom SSL certificates. Before Key Vault, we were manually renewing and uploading certificates every year. Nightmare.
With Key Vault, we:
Created a certificate in Key Vault connected to DigiCert. Configured automatic renewal 30 days before expiration. Referenced the Key Vault certificate in all App Service custom domains. Set up Azure Monitor alerts to notify us of any renewal issues.
Now it’s completely hands-off. Key Vault handles the entire certificate lifecycle, and App Services automatically pick up renewed certificates.
Use Case: Azure Function Fetching Secrets at Runtime
Let me share a pattern I use constantly: Azure Functions with Key Vault references. Instead of passing secrets as environment variables, you use a special syntax in your Function’s application settings:
@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/DatabasePassword/abc123)
When your Function cold-starts, Azure retrieves the secret from Key Vault using the Function’s managed identity. Your code sees it as a regular environment variable, but the actual secret never lives in the App Service configuration.
This pattern works identically for App Services, Logic Apps, and even Azure Kubernetes Service with the Azure Key Vault Provider for Secrets Store CSI Driver.
Reflection prompt: Can you identify which resource type (Secret, Key, or Certificate) suits your use case best? If you’re storing a database password, that’s a secret. Encrypting PII before database storage? That needs a key. Securing your web app with HTTPS? That’s a certificate.
Authentication and Access Control: Who Gets Access to What
Here’s where I see most security misconfigurations happen: access control. Azure Key Vault offers two models: Access Policies and RBAC (Role-Based Access Control). Understanding when to use each is crucial.
Azure AD-Based Authentication: No More Passwords
First principle: Azure Key Vault uses Azure Active Directory for all authentication. There are no local usernames or passwords. Every access request must present a valid Azure AD token.
In practice, this means your applications authenticate using:
Managed Identities (system-assigned or user-assigned) for Azure-hosted services. This is my default recommendation—no credentials in code at all.
Service Principals for applications running outside Azure or for CI/CD pipelines. You’ll need to manage the client secret or certificate, but at least it’s not embedded in source code.
User accounts for manual operations or development scenarios. Developers can use Azure CLI authentication (az login) to access Key Vault during local development.
The authentication flow I teach always follows this pattern: Your application obtains an Azure AD access token for the Key Vault resource. It presents this token in the Authorization header when making Key Vault API requests. Key Vault validates the token and checks permissions. If authorized, the operation proceeds.
Access Policies vs. RBAC: The Great Debate
When Key Vault first launched, Access Policies were the only option. You’d explicitly grant specific permissions (Get Secret, List Keys, etc.) to specific identities for a specific vault. It worked, but it didn’t scale well.
Access Policies give you granular control. You can grant a service principal permission to only read secrets, nothing else. You can allow one application to get and list secrets, but not delete them. The problem? Managing this across dozens of vaults and hundreds of identities becomes tedious.
RBAC (Azure’s role-based access control) treats Key Vault like any other Azure resource. You assign roles like “Key Vault Secrets User” or “Key Vault Administrator” at the vault level (or even subscription level). This integrates with your existing Azure governance model—same roles, same audit logs, same management portal.
When to Use Access Policies
I still use Access Policies in these scenarios:
Small teams with few vaults (less than five vaults, fewer than 20 identities). When you need very granular permissions that don’t fit standard RBAC roles (like allowing Get and List but denying Set and Delete). For legacy applications that were configured before RBAC support was added.
Example: Granting an app-only identity read access to specific secrets using Access Policies:
# Create a service principal
az ad sp create-for-rbac --name "MyApp"
# Grant it Get and List permissions on secrets only
az keyvault set-policy \
--name MyVault \
--spn <app-id-from-above> \
--secret-permissions get list
When to Use RBAC
RBAC is my recommendation for enterprise deployments:
Large organizations with centralized governance teams managing multiple vaults. When you want consistent access control across all Azure resources (not just Key Vault). If you’re using Azure Blueprints, Policies, or management groups to enforce security standards. For better integration with Azure AD Privileged Identity Management (PIM) for just-in-time access.
To enable RBAC on a Key Vault:
# Enable RBAC authorization model
az keyvault update \
--name MyVault \
--resource-group DevOpsRG \
--enable-rbac-authorization true
# Assign a role to a managed identity
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <managed-identity-principal-id> \
--scope /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyVault
The Key Vault Secrets User role allows reading secret values but not listing, creating, or deleting them. For administrative access, use Key Vault Administrator.
Real-World Example: Multi-Tier Application Access
In a three-tier application I architected (web front-end, API middle-tier, database), here’s how we configured access:
The web tier (App Service with system-assigned managed identity) got “Key Vault Secrets User” role to read API endpoint URLs and feature flags. The API tier (Azure Functions with user-assigned managed identity) got “Key Vault Secrets User” to read database connection strings and external API keys. The DevOps team got “Key Vault Administrator” role via Azure AD group membership for emergency access. CI/CD pipelines (GitHub Actions using federated credentials) got “Key Vault Secrets User” scoped to specific secrets needed for deployment validation.
Nobody had permissions they didn’t need. Every access generated audit logs. If someone left the team, we removed them from the Azure AD group—access to all vaults revoked immediately.
Quiz prompt: Which is more flexible for enterprise scale—Access Policies or RBAC? If you said RBAC, you’re thinking like an enterprise architect. Access Policies require per-vault configuration, while RBAC can be applied at subscription or resource group level, inheriting down to all child vaults.
Using Key Vault with Azure CLI and PowerShell
Theory is great, but let’s get our hands dirty with actual commands. I’ll show you the Azure CLI commands I use daily (PowerShell equivalents work similarly).
Creating Your First Key Vault
Before storing any secrets, you need a vault. Here’s how I typically create one:
# Create a resource group if you don't have one
az group create \
--name DevOpsRG \
--location eastus
# Create the Key Vault
az keyvault create \
--name MyDevOpsVault2025 \
--resource-group DevOpsRG \
--location eastus \
--enable-soft-delete true \
--enable-purge-protection true
Let me explain those flags: –enable-soft-delete true is critical. If someone accidentally (or maliciously) deletes a secret, it’s not gone forever—it goes into a “deleted but recoverable” state for 90 days. –enable-purge-protection true prevents anyone from permanently deleting secrets during that retention period. Even if an attacker compromises your credentials, they can’t erase audit trails.
Pro tip: Make your vault name globally unique. Key Vault DNS names must be unique across all of Azure. I append the year or a project code to avoid conflicts.
Adding and Retrieving Secrets
Now the fun part—actually storing secrets:
# Store a database password
az keyvault secret set \
--vault-name MyDevOpsVault2025 \
--name "DbPassword" \
--value "SuperSecret123!"
# Store a JSON connection string
az keyvault secret set \
--vault-name MyDevOpsVault2025 \
--name "CosmosConnection" \
--value '{"endpoint":"https://mydb.documents.azure.com","key":"abc123..."}'
Retrieving secrets is equally straightforward:
# Get the latest version of a secret
az keyvault secret show \
--vault-name MyDevOpsVault2025 \
--name "DbPassword" \
--query "value" \
--output tsv
That –query “value” –output tsv part is important. By default, the command returns JSON with metadata. For scripts, you usually just want the actual secret value.
Managing Secret Versions and Expiration
Here’s something many developers don’t know: Key Vault automatically versions secrets. Every time you update a secret, the old version remains accessible.
# Update a secret (creates a new version)
az keyvault secret set \
--vault-name MyDevOpsVault2025 \
--name "DbPassword" \
--value "NewPassword456!"
# List all versions of a secret
az keyvault secret list-versions \
--vault-name MyDevOpsVault2025 \
--name "DbPassword"
# Get a specific version
az keyvault secret show \
--vault-name MyDevOpsVault2025 \
--name "DbPassword" \
--version <version-id>
Why versions matter: During deployment rollbacks. If your new API version has issues and you need to roll back, you can temporarily use the previous secret version while you troubleshoot.
You should also set expiration dates on secrets to enforce rotation:
# Set a secret with expiration (30 days from now)
az keyvault secret set \
--vault-name MyDevOpsVault2025 \
--name "TempApiKey" \
--value "xyz789" \
--expires "2025-12-18T00:00:00Z"
Azure Monitor can alert you when secrets are approaching expiration. I configure alerts 7 days before to give teams time to rotate.
Assigning Permissions
We covered Access Policies and RBAC conceptually—here’s how to actually implement them:
For Access Policies:
# Grant yourself admin access (useful during initial setup)
az keyvault set-policy \
--name MyDevOpsVault2025 \
--upn your-email@company.com \
--secret-permissions all \
--key-permissions all \
--certificate-permissions all
# Grant an application managed identity read-only secret access
az keyvault set-policy \
--name MyDevOpsVault2025 \
--object-id <managed-identity-principal-id> \
--secret-permissions get list
For RBAC:
# First, enable RBAC mode
az keyvault update \
--name MyDevOpsVault2025 \
--resource-group DevOpsRG \
--enable-rbac-authorization true
# Assign yourself as admin
az role assignment create \
--role "Key Vault Administrator" \
--assignee your-email@company.com \
--scope /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyDevOpsVault2025
# Grant an application read access
az role assignment create \
--role "Key Vault Secrets User" \
--assignee <managed-identity-principal-id> \
--scope /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyDevOpsVault2025
PowerShell Equivalents
If your team prefers PowerShell:
# Create a Key Vault
New-AzKeyVault `
-Name "MyDevOpsVault2025" `
-ResourceGroupName "DevOpsRG" `
-Location "EastUS" `
-EnableSoftDelete `
-EnablePurgeProtection
# Add a secret
Set-AzKeyVaultSecret `
-VaultName "MyDevOpsVault2025" `
-Name "DbPassword" `
-SecretValue (ConvertTo-SecureString "SuperSecret123!" -AsPlainText -Force)
# Retrieve a secret
$secret = Get-AzKeyVaultSecret `
-VaultName "MyDevOpsVault2025" `
-Name "DbPassword"
$secret.SecretValue | ConvertFrom-SecureString -AsPlainText
Reflection: How can automating these steps in CI/CD pipelines improve security? Think about it: Instead of developers manually creating secrets (and potentially seeing them), your pipeline can provision vaults, generate strong random passwords, store them securely, and grant access—all without human eyes ever seeing the actual values.
Key Vault Integration with DevOps and CI/CD
This is where Key Vault transforms from “nice security feature” to “indispensable DevOps tool.” Integrating Key Vault into your pipelines means zero secrets in source control, version control, or pipeline definitions.
Azure DevOps Pipelines Integration
Azure DevOps has first-class support for Key Vault. You can link a Key Vault to your Azure DevOps pipeline and reference secrets as variables.
First, create a service connection in Azure DevOps:
Navigate to Project Settings → Service Connections → New service connection → Azure Resource Manager. Grant the service principal access to your Key Vault (either via Access Policy or RBAC “Key Vault Secrets User” role).
In your pipeline YAML:
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
- group: MyKeyVaultGroup # Variable group linked to Key Vault
steps:
- task: AzureKeyVault@2
inputs:
azureSubscription: 'MyAzureConnection'
KeyVaultName: 'MyDevOpsVault2025'
SecretsFilter: 'DbPassword,ApiKey' # Secrets to retrieve
RunAsPreJob: true # Fetch secrets before other tasks
- script: |
echo "Database password is available but not printed"
# Use $(DbPassword) in your scripts
# Never echo secrets!
displayName: 'Deploy Application'
The AzureKeyVault task fetches specified secrets and makes them available as pipeline variables. The secrets are masked in logs automatically—if someone tries to echo them, Azure DevOps redacts the output.
Important: Set RunAsPreJob: true so secrets are available in subsequent tasks. Without this, only that specific task has access.
GitHub Actions Integration
GitHub Actions requires a slightly different approach but achieves the same goal. You’ll use the Azure Login action followed by retrieving secrets.
First, set up Azure credentials as GitHub secrets (ironically, you need one secret to get all the others):
name: Deploy to Azure
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# Login to Azure using OIDC (no secrets in GitHub!)
- name: Azure Login
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
# Retrieve secrets from Key Vault
- name: Get Key Vault Secrets
uses: azure/CLI@v1
with:
inlineScript: |
echo "DB_PASSWORD=$(az keyvault secret show --vault-name MyDevOpsVault2025 --name DbPassword --query value -o tsv)" >> $GITHUB_ENV
echo "API_KEY=$(az keyvault secret show --vault-name MyDevOpsVault2025 --name ApiKey --query value -o tsv)" >> $GITHUB_ENV
- name: Deploy Application
run: |
echo "Deploying with credentials from Key Vault"
# Use $DB_PASSWORD and $API_KEY in deployment commands
Pro tip: Use federated credentials (OIDC) instead of service principal secrets. This way, GitHub doesn’t store any long-lived Azure credentials at all—authentication happens via workload identity federation.
Terraform Integration
If you’re using Terraform for infrastructure as code, you can retrieve Key Vault secrets during deployment:
# Data source to access Key Vault
data "azurerm_key_vault" "main" {
name = "MyDevOpsVault2025"
resource_group_name = "DevOpsRG"
}
# Retrieve a secret
data "azurerm_key_vault_secret" "db_password" {
name = "DbPassword"
key_vault_id = data.azurerm_key_vault.main.id
}
# Use the secret in a resource
resource "azurerm_app_service" "api" {
name = "my-api-service"
location = "East US"
resource_group_name = "DevOpsRG"
app_service_plan_id = azurerm_app_service_plan.main.id
app_settings = {
"DATABASE_CONNECTION" = data.azurerm_key_vault_secret.db_password.value
}
}
Important note: While this works, the secret value ends up in Terraform state files. For production, use Key Vault references in App Service instead:
resource "azurerm_app_service" "api" {
# ... other config ...
app_settings = {
"DATABASE_CONNECTION" = "@Microsoft.KeyVault(SecretUri=${data.azurerm_key_vault_secret.db_password.id})"
}
identity {
type = "SystemAssigned"
}
}
This way, the App Service retrieves the secret directly from Key Vault at runtime, and it never touches Terraform state.
Real-World Example: Secure Azure App Service Deployment
Let me share a complete pipeline I built for deploying a containerized application:
The pipeline creates an App Service with system-assigned managed identity. It grants that identity “Key Vault Secrets User” role on our vault. It references database connection strings, API keys, and feature flags using Key Vault references in app settings. During deployment, the container image pulls from Azure Container Registry (authenticated via managed identity). When the app starts, it fetches secrets from Key Vault (again via managed identity).
Result: Zero secrets in source control, pipelines, or container images. Everything is dynamically retrieved from Key Vault with full audit logging.
Callout: 🚀 Pro Tip — Never store credentials in pipeline variables. Always fetch them dynamically from Key Vault. Pipeline variables can be viewed by anyone with pipeline edit permissions, and they’re logged in plain text if you’re not careful.
Security, Monitoring, and Compliance
Creating a Key Vault and storing secrets is just the beginning. Maintaining security and compliance requires ongoing monitoring and governance.
Azure Policy for Key Vault Governance
Azure Policy lets you enforce standards across all Key Vaults in your subscription or management group. I typically deploy these policies:
Require soft-delete enabled: Prevents anyone from creating vaults without soft-delete protection.
Require purge protection: Ensures deleted secrets can’t be immediately purged.
Require network restrictions: Enforces private endpoints or firewall rules on all vaults.
Require diagnostic logging: Ensures all vaults send logs to Azure Monitor or Log Analytics.
Here’s how to assign a built-in policy requiring purge protection:
az policy assignment create \
--name "RequirePurgeProtection" \
--policy "/providers/Microsoft.Authorization/policyDefinitions/0b60c0b2-2dc2-4e1c-b5c9-abbed971de53" \
--scope "/subscriptions/<subscription-id>"
Now any Key Vault created without purge protection will be flagged as non-compliant. In Deny mode, creation would be blocked entirely.
Logging and Monitoring with Azure Monitor
Every access to Key Vault generates diagnostic logs. These logs capture who accessed what, when, from where, and whether the operation succeeded. For compliance audits, this is gold.
Enable diagnostic logging:
# Create a Log Analytics workspace if you don't have one
az monitor log-analytics workspace create \
--resource-group DevOpsRG \
--workspace-name KeyVaultLogs
# Enable diagnostics on the vault
az monitor diagnostic-settings create \
--name KeyVaultDiagnostics \
--resource /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyDevOpsVault2025 \
--workspace <workspace-id> \
--logs '[{"category": "AuditEvent","enabled": true}]' \
--metrics '[{"category": "AllMetrics","enabled": true}]'
Now you can query logs in Log Analytics:
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName == "SecretGet"
| project TimeGenerated, CallerIPAddress, identity_claim_http_schemas_microsoft_com_identity_claims_objectidentifier, ResultSignature
| order by TimeGenerated desc
This query shows who retrieved secrets, their IP address, and whether the operation succeeded (ResultSignature = 200) or failed.
Setting Up Alerts
I configure these alerts as standard:
Secret near expiration: Alert 7 days before any secret expires.
Failed authentication attempts: Alert on repeated failed access attempts from unusual IP addresses.
Unexpected high volume of operations: Alert if a single identity makes more than 1000 requests in an hour (possible credential leak).
Configuration changes: Alert when access policies or RBAC roles are modified.
Example alert for expiring secrets:
az monitor metrics alert create \
--name "SecretExpiringSoon" \
--resource-group DevOpsRG \
--scopes /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyDevOpsVault2025 \
--condition "avg DaysToExpiry < 7" \
--window-size 1h \
--evaluation-frequency 1h \
--action-group <action-group-id>
Soft-Delete and Purge Protection
I mentioned these earlier, but they’re so important I’m dedicating a section to them. Soft-delete means deleted secrets aren’t immediately destroyed—they’re retained for 90 days. During this period, you can list and recover them.
Recovering a deleted secret:
# List deleted secrets
az keyvault secret list-deleted --vault-name MyDevOpsVault2025
# Recover a deleted secret
az keyvault secret recover \
--vault-name MyDevOpsVault2025 \
--name "AccidentallyDeleted"
Purge protection prevents anyone from permanently deleting (purging) secrets during the retention period. Even with “Key Vault Administrator” role, you can’t bypass this. It’s your insurance policy against ransomware or disgruntled employees.
Key Rotation Policies
Secrets should rotate regularly. Many compliance frameworks (PCI-DSS, SOC 2) require rotation every 90 days. Key Vault supports automatic rotation for managed certificates (it handles renewal with the CA), but for secrets, you’ll need to implement rotation.
My recommended approach:
Use Event Grid to trigger an Azure Function when a secret is about to expire. The function generates a new secret (e.g., new database password), updates Key Vault, and updates the target service (e.g., Azure SQL password).
For manual rotation, use secret versions:
# Create a new version with rotated value
az keyvault secret set \
--vault-name MyDevOpsVault2025 \
--name "DbPassword" \
--value "NewRotatedPassword789"
Applications using the secret will automatically get the new version on their next retrieval (unless they’re pinning to a specific version, which you shouldn’t do).
Secret Versioning Strategy
Speaking of versions, here’s my strategy: Always reference secrets without specifying a version (get the latest). This ensures applications automatically pick up rotated secrets. Retain old versions for 30 days to support rollbacks. After 30 days, explicitly delete old versions to reduce clutter and potential confusion.
Reflection: How often do you rotate secrets or review Key Vault access policies? If the answer is “never” or “when someone leaves,” you’re doing it wrong. Quarterly access reviews and 90-day secret rotation should be in your calendar like recurring meetings.
Advanced Features: Taking Key Vault to the Next Level
Once you’ve mastered the basics, these advanced features unlock additional security and functionality.
Managed HSM for Compliance Workloads
Azure Key Vault Managed HSM is the premium tier—a fully managed, single-tenant HSM (Hardware Security Module) that meets FIPS 140-2 Level 3 certification. Standard Key Vaults use software-protected keys (FIPS 140-2 Level 1). For regulated industries like finance or healthcare, Managed HSM might be required.
The key difference: In standard Key Vault, Microsoft manages the underlying HSM infrastructure. With Managed HSM, you have exclusive control over the HSM, and cryptographic operations happen within a tamper-resistant hardware boundary.
Creating a Managed HSM:
az keyvault create --hsm-name MyManagedHSM \
--resource-group DevOpsRG \
--location eastus \
--administrators <admin-object-id> \
--retention-days 90
Cost note: Managed HSM is significantly more expensive (starts around $2,000/month). Only use it if compliance mandates require Level 3 certification.
Private Endpoints for Network Isolation
By default, Key Vault is accessible over the public internet (with authentication and authorization still required). For zero-trust architectures, you can disable public access entirely and use private endpoints.
A private endpoint assigns a private IP address from your virtual network to the Key Vault. Traffic between your applications and Key Vault never leaves the Azure backbone.
Creating a private endpoint:
# Disable public access
az keyvault update \
--name MyDevOpsVault2025 \
--resource-group DevOpsRG \
--public-network-access Disabled
# Create private endpoint
az network private-endpoint create \
--name KeyVaultPrivateEndpoint \
--resource-group DevOpsRG \
--vnet-name MyVNet \
--subnet PrivateEndpointSubnet \
--private-connection-resource-id /subscriptions/<sub-id>/resourceGroups/DevOpsRG/providers/Microsoft.KeyVault/vaults/MyDevOpsVault2025 \
--group-id vault \
--connection-name KeyVaultConnection
Now only resources within your VNet (or peered VNets) can access Key Vault. This is essential for regulated workloads where data must not traverse the public internet.
Integration with Azure Disk Encryption
Azure Disk Encryption uses BitLocker (Windows) or dm-crypt (Linux) to encrypt VM disks. The encryption keys are stored in Key Vault.
Enabling disk encryption on a VM:
az vm encryption enable \
--resource-group DevOpsRG \
--name MyVM \
--disk-encryption-keyvault MyDevOpsVault2025
Key Vault stores the disk encryption key, and the VM retrieves it at boot. If someone steals the physical disk or takes a snapshot, they can’t decrypt it without access to Key Vault.
Key Vault References in App Service and Functions
This is my favorite feature for containerized workloads. Instead of storing secrets as environment variables, you use Key Vault references:
@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/DbPassword/)
When the App Service or Function starts, it resolves these references dynamically. If the secret rotates in Key Vault, restarting the app picks up the new value—no redeployment needed.
Setting this up in an App Service:
az webapp config appsettings set \
--name MyWebApp \
--resource-group DevOpsRG \
--settings DATABASE_PASSWORD="@Microsoft.KeyVault(SecretUri=https://MyDevOpsVault2025.vault.azure.net/secrets/DbPassword/)"
Make sure the App Service has a managed identity with “Key Vault Secrets User” role.
Example: Using Managed HSM for Financial Services
I worked with a fintech company processing credit card transactions. PCI-DSS compliance required cryptographic keys in FIPS 140-2 Level 3 HSMs. We implemented Managed HSM with:
Customer-managed keys for encrypting cardholder data at rest in Azure SQL Database. Hardware-backed signing keys for generating tamper-proof audit logs (each transaction signed with HSM key). Bring-your-own-key (BYOK) import process where their on-premises HSM-generated keys were securely imported to Azure Managed HSM.
The architecture passed PCI-DSS audit on the first try because the auditors could verify that key material never existed outside HSMs, all cryptographic operations were logged, and access was tightly controlled via Azure AD and RBAC.
Common Mistakes to Avoid
I’ve seen these mistakes repeatedly. Learn from others’ pain:
Mistake 1: Leaving Purge Protection Disabled
The problem: Someone (malicious or accidental) deletes secrets from Key Vault. Without purge protection, they can immediately purge them permanently, destroying all versions and making recovery impossible.
The fix: Always enable purge protection when creating vaults:
az keyvault create --enable-purge-protection true ...
Once enabled, it cannot be disabled. That’s intentional—it’s like a safety lock on a firearm.
Mistake 2: Hardcoding Key Vault URIs
The problem: You hardcode https://prod-vault.vault.azure.net in your application code. Now your app only works in production, not development or staging.
The fix: Store the Key Vault URI as an environment variable or app setting:
const vaultUrl = process.env.KEY_VAULT_URI || "https://dev-vault.vault.azure.net";
Even better, use different vaults for each environment (dev, staging, prod) and configure the correct URI per deployment.
Mistake 3: Overusing Access Policies Instead of RBAC
The problem: You manage 50 Key Vaults, each with 20 access policies for different applications and teams. Making changes is a nightmare—did you remember to update all 50 vaults?
The fix: Migrate to RBAC. Assign roles at the resource group or subscription level. Use Azure AD groups for team-based access. Let RBAC inheritance do the heavy lifting.
Mistake 4: Not Monitoring Secret Expiration
The problem: Secrets expire silently. Your application suddenly can’t authenticate because the API key expired two weeks ago, and nobody noticed until production broke.
The fix: Set expiration dates on all secrets. Configure Azure Monitor alerts for secrets expiring within 7 days. Review expiring secrets weekly during ops meetings.
Mistake 5: Forgetting to Restrict Public Network Access
The problem: Your Key Vault is accessible from any IP address on the internet. While authentication is still required, you’re exposed to credential stuffing attacks and compliance violations.
The fix: Use network ACLs to allow only specific IP ranges:
az keyvault network-rule add \
--name MyDevOpsVault2025 \
--resource-group DevOpsRG \
--ip-address 203.0.113.0/24
Or disable public access entirely and use private endpoints.
Mistake 6: Storing Non-Secret Data in Key Vault
The problem: You store configuration data (URLs, port numbers, feature flags) in Key Vault because “everything should be centralized.”
The issue: Key Vault charges per API call. Fetching non-sensitive config data racks up costs unnecessarily. Plus, it’s overkill—these values don’t need HSM-backed encryption.
The fix: Use Azure App Configuration for non-secret settings and Key Vault for actual secrets. App Configuration even has built-in Key Vault references for sensitive values.
Mistake 7: Not Testing Disaster Recovery
The problem: You assume Key Vault backups work. Then one day you need to recover a deleted vault or secret, and you realize you don’t know how.
The fix: Periodically test recovery procedures:
# Simulate deletion
az keyvault secret delete --name TestSecret --vault-name MyDevOpsVault2025
# List deleted secrets
az keyvault secret list-deleted --vault-name MyDevOpsVault2025
# Recover it
az keyvault secret recover --name TestSecret --vault-name MyDevOpsVault2025
Document the process and ensure your team knows how to execute it under pressure.
Callout: 💡 Always enable purge protection—it’s your last defense against accidental or malicious deletion. I’ve seen production outages that lasted hours because someone purged secrets thinking they were in a test vault. With purge protection, that can’t happen.
Pricing and Cost Optimization
Let’s talk money. Key Vault pricing is straightforward but can add up if you’re not careful.
Standard Tier Pricing Model
Secrets, Keys, and Certificates storage: First 25,000 operations per month are approximately $0.03 per 10,000 operations. After that, it’s $0.03 per 10,000 operations.
Key operations (encrypt, decrypt, sign, verify): $0.03 per 10,000 operations.
Certificate operations: Automated renewals are included. Manual certificate operations follow standard pricing.
Advanced key types (HSM-backed keys in Standard tier): $1 per key per month.
The takeaway: Storage is cheap. Operations cost real money if you’re inefficient.
Managed HSM Pricing
Managed HSM pool: Approximately $2,000-$4,000 per month per HSM pool (varies by region).
Operations: Similar per-operation costs as Standard tier.
Managed HSM makes sense only for compliance-driven workloads. Don’t use it “just because it’s more secure”—the security improvement is marginal unless you specifically need FIPS 140-2 Level 3.
Cost Optimization Strategies
Here’s how I keep Key Vault costs reasonable:
Cache secrets in application memory. Don’t fetch from Key Vault on every request. Fetch once at application startup or every few hours. Use in-memory caching with TTL-based refresh.
// Bad: Fetch on every request
app.get('/api/data', async (req, res) => {
const secret = await keyVaultClient.getSecret('DbPassword');
// Use secret...
});
// Good: Cache and refresh periodically
let cachedSecret = null;
let lastRefresh = 0;
async function getSecret() {
const now = Date.now();
if (!cachedSecret || now - lastRefresh > 3600000) { // 1 hour
cachedSecret = await keyVaultClient.getSecret('DbPassword');
lastRefresh = now;
}
return cachedSecret;
}
Batch operations where possible. If you need multiple secrets, fetch them together rather than making separate calls. Some SDKs support batch retrieval.
Use App Service / Functions Key Vault references. These fetch secrets at application start and cache them. You’re not charged for each environment variable read—only the initial fetch.
Audit and clean up unused secrets. I run monthly audits to identify secrets that haven’t been accessed in 90 days. If nobody’s using them, delete them to reduce clutter.
Optimize certificate renewal. Automated renewals are cost-effective. Manual renewals incur API call costs each time you upload a new certificate.
Right-size your tier. Don’t use Managed HSM unless compliance requires it. Standard tier is sufficient for 95% of workloads.
Indirect Cost Savings
The real savings from Key Vault aren’t on the Azure bill—they’re from avoiding security incidents. A single data breach can cost millions in remediation, legal fees, regulatory fines, and reputation damage.
When I pitch Key Vault to finance teams, I frame it this way: “We’re spending $100/month on Key Vault to protect $10 million in customer data. What’s the ROI on avoiding even a small breach?”
That usually ends the cost discussion.
Bringing It All Together
We’ve covered a lot of ground. Let’s recap the key principles:
Azure Key Vault is your centralized secrets management service. It stores secrets, cryptographic keys, and certificates with enterprise-grade security. All access is authenticated via Azure AD—no local passwords.
Use managed identities wherever possible. System-assigned or user-assigned managed identities eliminate the need to manage credentials in your applications. Your code never sees passwords or API keys.
Enable soft-delete and purge protection from day one. These are your safety nets against accidental or malicious deletion. They can’t be retroactively applied to existing secrets, so enable them when creating vaults.
Integrate Key Vault into your CI/CD pipelines. Fetch secrets dynamically during deployment rather than storing them as pipeline variables. This prevents credential exposure in logs and source control.
Monitor access and set alerts. Use Azure Monitor and Log Analytics to track who accesses what. Configure alerts for expiring secrets, failed authentication attempts, and configuration changes.
Adopt RBAC for enterprise scale. Access Policies work for small teams, but RBAC integrates with broader Azure governance and scales much better.
Cache secrets intelligently to control costs. Don’t fetch from Key Vault on every API request. Cache in memory and refresh periodically.
Plan for disaster recovery. Test secret recovery procedures. Document how to recover deleted vaults and secrets. Make sure your team knows the process.
Think of Azure Key Vault as your application’s digital guardian—guarding secrets, enforcing compliance, and enabling zero-trust DevOps. When properly configured, it becomes invisible infrastructure that just works, protecting your most sensitive data without requiring constant attention.
As you implement Key Vault in your projects, remember the foundational principle: Security is not a feature you add later—it’s a foundation you build on from day one. Key Vault is that foundation for secrets management.
Frequently Asked Questions (FAQs)
What is Azure Key Vault?
Azure Key Vault is a cloud service from Microsoft for securely storing and accessing secrets, cryptographic keys, and certificates. It provides centralized secrets management with hardware-backed security, access control via Azure Active Directory, and comprehensive audit logging. Key Vault helps eliminate hardcoded credentials in applications and enables zero-trust security architectures.
How does Azure Key Vault work?
Azure Key Vault authenticates all access requests using Azure Active Directory tokens. When your application needs a secret, it presents an Azure AD token (obtained via managed identity or service principal). Key Vault validates the token, checks permissions (via Access Policies or RBAC), and if authorized, decrypts the secret and returns it over HTTPS. Secrets are encrypted at rest, and all operations generate audit logs for compliance tracking.
How to use Azure Key Vault with Azure DevOps pipelines?
In Azure DevOps, create a service connection to your Azure subscription and grant the service principal access to your Key Vault. In your pipeline YAML, use the AzureKeyVault@2 task to fetch secrets before other tasks run. Reference secrets as pipeline variables using $(SecretName) syntax. Azure DevOps automatically masks secret values in logs to prevent accidental exposure.
Is Azure Key Vault free?
Azure Key Vault is not free, but it has a pay-per-use pricing model with low costs for typical usage. The Standard tier costs approximately $0.03 per 10,000 operations, with additional charges for HSM-backed keys ($1 per key per month). There is no base cost for the vault itself. Managed HSM is significantly more expensive, starting around $2,000 per month, and is intended only for compliance-driven workloads requiring FIPS 140-2 Level 3 certification.
What’s the difference between Access Policies and RBAC in Key Vault?
Access Policies are Key Vault-specific permissions that grant granular access to secrets, keys, and certificates at the vault level. You explicitly define which operations each identity can perform. RBAC (Role-Based Access Control) treats Key Vault like any other Azure resource, using standard Azure roles like “Key Vault Secrets User” or “Key Vault Administrator.” RBAC is more flexible for enterprise environments because it integrates with Azure governance, supports inheritance from resource groups or subscriptions, and works with Azure AD Privileged Identity Management. For new deployments, Microsoft recommends RBAC over Access Policies.
Your Next Steps
Ready to implement Azure Key Vault in your DevOps workflow? Here’s what I recommend:
Start with a sandbox environment. Create a test Key Vault, store a few secrets, and practice retrieving them via Azure CLI and in application code. Break things. Delete secrets and practice recovery. Get comfortable with the operations before touching production.
Audit your current secrets management. Where are secrets stored today? Configuration files? Environment variables? Pipeline definitions? Make a list of every credential your applications use. This becomes your migration checklist.
Design your Key Vault strategy. How many vaults do you need? One per environment? One per application? One per team? There’s no one-size-fits-all answer, but generally, separate production from non-production environments and separate applications with different compliance requirements.
Implement managed identities. This is non-negotiable. Convert your applications to use system-assigned or user-assigned managed identities for accessing Key Vault. Eliminate service principal secrets from your codebase.
Integrate with CI/CD pipelines. Start with one deployment pipeline. Migrate secrets from pipeline variables to Key Vault references. Once you see how clean and secure it is, roll it out to other pipelines.
Enable monitoring and alerting. Don’t wait for an incident. Configure diagnostic logging and alerts from day one. Set up automated reports showing who accessed which secrets in the past week.
Document your processes. Write runbooks for common operations: creating secrets, rotating credentials, recovering deleted items, granting access to new team members. Future-you will thank present-you.
👉 Take the Free Azure Key Vault Hands-On Tutorial
Want to go beyond theory and actually build a production-ready Key Vault implementation? I’ve created a hands-on tutorial that walks you through:
Setting up Key Vault with best-practice security configurations. Integrating secrets into Azure App Services using managed identities. Automating secret rotation with Azure Functions and Event Grid. Configuring monitoring, alerting, and compliance policies. Building a secure CI/CD pipeline with GitHub Actions pulling secrets from Key Vault.
Learn how to secure secrets, keys, and certificates the DevOps way.
This isn’t just another tutorial—it’s the practical knowledge I wish I had when I started managing production workloads on Azure. Every example comes from real-world scenarios I’ve implemented across dozens of enterprise projects.
Your applications deserve better than plaintext secrets scattered across config files. Let’s build something secure together.
Ready to level up your Azure security game? Dive into the hands-on tutorial now.
Written by Srikanth Ch, Senior DevOps Engineer at TheDevOpsTooling.com. Helping DevOps engineers build secure, scalable, and compliant cloud infrastructure—one tutorial at a time.

One Comment