2026-01-27 17:35:45 -05:00
---
name : azure-keyvault
description : Manage secrets and certificates in Azure Key Vault. Configure access policies, integrate with Azure services, and implement secure secret management. Use when managing secrets in Azure environments.
license : MIT
metadata :
author : devops-skills
version : "1.0"
---
# Azure Key Vault
Securely store and manage secrets, keys, and certificates in Azure.
## When to Use This Skill
Use this skill when:
2026-03-24 18:02:50 -04:00
- Managing secrets, encryption keys, or certificates in Azure
- Implementing centralized secret management for Azure services
- Integrating secrets into AKS, App Service, or Azure Functions
- Encrypting data with customer-managed keys (CMK)
- Meeting compliance requirements for key management (FIPS 140-2)
2026-01-27 17:35:45 -05:00
## Prerequisites
2026-03-24 18:02:50 -04:00
- Azure subscription with appropriate permissions
- Azure CLI installed (`az` command)
- Contributor or Key Vault Administrator role for vault management
- Managed identity configured for application access
- Understanding of Azure RBAC vs. Key Vault access policies
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
## Vault Creation and Configuration
2026-01-27 17:35:45 -05:00
```bash
2026-03-24 18:02:50 -04:00
# Create a resource group
az group create --name rg-secrets --location eastus
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Create Key Vault with RBAC authorization (recommended)
az keyvault create \
--name myapp-vault-prod \
--resource-group rg-secrets \
--location eastus \
--enable-rbac-authorization true \
--enable-soft-delete true \
--retention-days 90 \
--enable-purge-protection true \
--sku premium # Use premium for HSM-backed keys
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Create Key Vault with access policies (legacy)
az keyvault create \
--name myapp-vault-dev \
--resource-group rg-secrets \
--location eastus \
--enable-soft-delete true \
--retention-days 30
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Enable private endpoint (no public access)
az keyvault update \
--name myapp-vault-prod \
--resource-group rg-secrets \
--public-network-access Disabled
# Enable diagnostics logging
az monitor diagnostic-settings create \
--name kv-diagnostics \
--resource "/subscriptions/{sub}/resourceGroups/rg-secrets/providers/Microsoft.KeyVault/vaults/myapp-vault-prod" \
--workspace "/subscriptions/{sub}/resourceGroups/rg-monitor/providers/Microsoft.OperationalInsights/workspaces/security-logs" \
--logs '[{"category":"AuditEvent","enabled":true,"retentionPolicy":{"enabled":true,"days":365}}]'
```
## Secret Management
```bash
# Set a secret
az keyvault secret set \
--vault-name myapp-vault-prod \
--name db-password \
--value "S3cur3P@ssw0rd!" \
--content-type "text/plain" \
--tags Environment = production Team = platform
# Set a multi-line secret (JSON credentials)
az keyvault secret set \
--vault-name myapp-vault-prod \
--name db-credentials \
--value '{"username":"dbadmin","password":"S3cur3P@ss!","host":"db.postgres.database.azure.com","port":5432}'
# Get secret value
az keyvault secret show \
--vault-name myapp-vault-prod \
--name db-password \
--query value -o tsv
# Get specific version
az keyvault secret show \
--vault-name myapp-vault-prod \
--name db-password \
--version abc123def456
# List all secrets
az keyvault secret list --vault-name myapp-vault-prod -o table
# List secret versions
az keyvault secret list-versions \
--vault-name myapp-vault-prod \
--name db-password -o table
# Set expiration date
az keyvault secret set-attributes \
--vault-name myapp-vault-prod \
--name api-key \
--expires "2026-01-01T00:00:00Z"
# Disable a secret (without deleting)
az keyvault secret set-attributes \
--vault-name myapp-vault-prod \
--name old-api-key \
--enabled false
# Delete a secret (soft-delete)
az keyvault secret delete \
--vault-name myapp-vault-prod \
--name old-api-key
# Recover a deleted secret
az keyvault secret recover \
--vault-name myapp-vault-prod \
--name old-api-key
# Purge a deleted secret (permanent, requires purge protection to be off)
az keyvault secret purge \
--vault-name myapp-vault-prod \
--name old-api-key
# Backup and restore
az keyvault secret backup \
--vault-name myapp-vault-prod \
--name db-password \
--file db-password.backup
az keyvault secret restore \
--vault-name myapp-vault-prod \
--file db-password.backup
```
## Key Management
```bash
# Create an RSA key for encryption
az keyvault key create \
--vault-name myapp-vault-prod \
--name data-encryption-key \
--kty RSA \
--size 4096 \
--ops encrypt decrypt wrapKey unwrapKey
# Create an EC key for signing
az keyvault key create \
--vault-name myapp-vault-prod \
--name signing-key \
--kty EC \
--curve P-256 \
--ops sign verify
# Import an existing key
az keyvault key import \
--vault-name myapp-vault-prod \
--name imported-key \
--pem-file key.pem
# Encrypt data
az keyvault key encrypt \
--vault-name myapp-vault-prod \
--name data-encryption-key \
--algorithm RSA-OAEP-256 \
--value "base64-encoded-plaintext"
# Rotate a key
az keyvault key rotate \
--vault-name myapp-vault-prod \
--name data-encryption-key
# Set key rotation policy
az keyvault key rotation-policy update \
--vault-name myapp-vault-prod \
--name data-encryption-key \
--value '{
"lifetimeActions": [
{
"trigger": {"timeBeforeExpiry": "P30D"},
"action": {"type": "Notify"}
},
{
"trigger": {"timeAfterCreate": "P90D"},
"action": {"type": "Rotate"}
}
],
"attributes": {"expiryTime": "P180D"}
}'
```
## Certificate Management
```bash
# Create a self-signed certificate
az keyvault certificate create \
--vault-name myapp-vault-prod \
--name app-tls-cert \
--policy '{
"issuerParameters": {"name": "Self"},
"keyProperties": {"exportable": true, "keySize": 4096, "keyType": "RSA"},
"secretProperties": {"contentType": "application/x-pkcs12"},
"x509CertificateProperties": {
"subject": "CN=app.example.com",
"subjectAlternativeNames": {"dnsNames": ["app.example.com", "*.app.example.com"]},
"validityInMonths": 12,
"keyUsage": ["digitalSignature", "keyEncipherment"],
"ekus": ["1.3.6.1.5.5.7.3.1"]
},
"lifetimeActions": [
{"trigger": {"daysBeforeExpiry": 30}, "action": {"actionType": "AutoRenew"}}
]
}'
# Import a certificate
az keyvault certificate import \
--vault-name myapp-vault-prod \
--name imported-cert \
--file certificate.pfx \
--password "pfx-password"
# Download certificate
az keyvault certificate download \
--vault-name myapp-vault-prod \
--name app-tls-cert \
--file cert.pem \
--encoding PEM
# List certificates
az keyvault certificate list --vault-name myapp-vault-prod -o table
```
## Access Policies and RBAC
### RBAC (Recommended)
```bash
# Grant secret reader access to a managed identity
az role assignment create \
--role "Key Vault Secrets User" \
--assignee-object-id " $( az identity show -g rg-app -n myapp-identity --query principalId -o tsv) " \
--scope "/subscriptions/{sub}/resourceGroups/rg-secrets/providers/Microsoft.KeyVault/vaults/myapp-vault-prod"
# Grant admin access to security team
az role assignment create \
--role "Key Vault Administrator" \
--assignee "security-team@example.com" \
--scope "/subscriptions/{sub}/resourceGroups/rg-secrets/providers/Microsoft.KeyVault/vaults/myapp-vault-prod"
# Available Key Vault RBAC roles:
# - Key Vault Administrator (full management)
# - Key Vault Secrets Officer (manage secrets)
# - Key Vault Secrets User (read secrets)
# - Key Vault Certificates Officer (manage certs)
# - Key Vault Crypto Officer (manage keys)
# - Key Vault Crypto User (use keys for encrypt/decrypt)
# - Key Vault Reader (read metadata only)
```
### Access Policies (Legacy)
```bash
# Grant secret access via access policy
az keyvault set-policy \
--name myapp-vault-prod \
--object-id " $( az identity show -g rg-app -n myapp-identity --query principalId -o tsv) " \
--secret-permissions get list
# Grant key access
az keyvault set-policy \
--name myapp-vault-prod \
--object-id " $OBJECT_ID " \
--key-permissions get unwrapKey wrapKey
# Grant certificate access
az keyvault set-policy \
--name myapp-vault-prod \
--object-id " $OBJECT_ID " \
--certificate-permissions get list
2026-01-27 17:35:45 -05:00
```
## Application Integration
2026-03-24 18:02:50 -04:00
### Python SDK
2026-01-27 17:35:45 -05:00
```python
2026-03-24 18:02:50 -04:00
from azure.identity import DefaultAzureCredential , ManagedIdentityCredential
2026-01-27 17:35:45 -05:00
from azure.keyvault.secrets import SecretClient
2026-03-24 18:02:50 -04:00
from azure.keyvault.keys import KeyClient
from azure.keyvault.certificates import CertificateClient
2026-01-27 17:35:45 -05:00
2026-03-24 18:02:50 -04:00
# Use DefaultAzureCredential (works locally and in Azure)
2026-01-27 17:35:45 -05:00
credential = DefaultAzureCredential ()
2026-03-24 18:02:50 -04:00
vault_url = "https://myapp-vault-prod.vault.azure.net/"
# Secrets
secret_client = SecretClient ( vault_url = vault_url , credential = credential )
db_password = secret_client . get_secret ( "db-password" )
print ( f "Secret value: { db_password . value } " )
# Get specific version
specific = secret_client . get_secret ( "db-password" , version = "abc123" )
# List secrets
for secret_properties in secret_client . list_properties_of_secrets ():
print ( f "Secret: { secret_properties . name } , Enabled: { secret_properties . enabled } " )
# Keys
key_client = KeyClient ( vault_url = vault_url , credential = credential )
from azure.keyvault.keys.crypto import CryptographyClient , EncryptionAlgorithm
key = key_client . get_key ( "data-encryption-key" )
crypto_client = CryptographyClient ( key , credential = credential )
# Encrypt data
plaintext = b "sensitive data"
result = crypto_client . encrypt ( EncryptionAlgorithm . rsa_oaep_256 , plaintext )
ciphertext = result . ciphertext
# Decrypt data
decrypted = crypto_client . decrypt ( EncryptionAlgorithm . rsa_oaep_256 , ciphertext )
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
### .NET SDK
```csharp
using Azure.Identity ;
using Azure.Security.KeyVault.Secrets ;
var credential = new DefaultAzureCredential ();
var client = new SecretClient ( new Uri ( "https://myapp-vault-prod.vault.azure.net/" ), credential );
KeyVaultSecret secret = await client . GetSecretAsync ( "db-password" );
string password = secret . Value ;
```
## Kubernetes Integration (AKS)
### Secrets Store CSI Driver
2026-01-27 17:35:45 -05:00
```yaml
2026-03-24 18:02:50 -04:00
# SecretProviderClass for AKS with managed identity
2026-01-27 17:35:45 -05:00
apiVersion : secrets-store.csi.x-k8s.io/v1
kind : SecretProviderClass
metadata :
2026-03-24 18:02:50 -04:00
name : azure-keyvault-secrets
namespace : production
2026-01-27 17:35:45 -05:00
spec :
provider : azure
parameters :
2026-03-24 18:02:50 -04:00
usePodIdentity : "false"
useVMManagedIdentity : "true"
userAssignedIdentityID : "<managed-identity-client-id>"
keyvaultName : "myapp-vault-prod"
cloudName : ""
2026-01-27 17:35:45 -05:00
objects : |
array:
- |
objectName: db-password
objectType: secret
2026-03-24 18:02:50 -04:00
objectVersion: ""
- |
objectName: api-key
objectType: secret
- |
objectName: app-tls-cert
objectType: secret
tenantId : "<azure-tenant-id>"
secretObjects :
- secretName : db-secrets
type : Opaque
data :
- objectName : db-password
key : password
- objectName : api-key
key : api-key
- secretName : tls-secret
type : kubernetes.io/tls
data :
- objectName : app-tls-cert
key : tls.crt
---
# Pod using the secrets
apiVersion : v1
kind : Pod
metadata :
name : myapp
namespace : production
spec :
serviceAccountName : myapp-sa
containers :
- name : myapp
image : ghcr.io/acme/myapp:v1.0.0
env :
- name : DB_PASSWORD
valueFrom :
secretKeyRef :
name : db-secrets
key : password
volumeMounts :
- name : secrets-store
mountPath : "/mnt/secrets-store"
readOnly : true
volumes :
- name : secrets-store
csi :
driver : secrets-store.csi.k8s.io
readOnly : true
volumeAttributes :
secretProviderClass : "azure-keyvault-secrets"
2026-01-27 17:35:45 -05:00
```
2026-03-24 18:02:50 -04:00
## Terraform Configuration
```hcl
resource "azurerm_key_vault" "main" {
name = "myapp-vault-prod"
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"
enable_rbac_authorization = true
purge_protection_enabled = true
soft_delete_retention_days = 90
public_network_access_enabled = false
network_acls {
bypass = "AzureServices"
default_action = "Deny"
ip_rules = [ "203.0.113.0/24" ]
virtual_network_subnet_ids = [ azurerm_subnet . app . id ]
}
}
resource "azurerm_key_vault_secret" "db_password" {
name = "db-password"
value = var . db_password
key_vault_id = azurerm_key_vault . main . id
content_type = "text/plain"
expiration_date = "2026-01-01T00:00:00Z"
tags = {
environment = "production"
rotation = "enabled"
}
}
resource "azurerm_role_assignment" "app_secrets_user" {
scope = azurerm_key_vault . main . id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity . app . principal_id
}
```
## Troubleshooting
| Problem | Cause | Solution |
|---------|-------|----------|
| "Access denied" when reading secrets | Missing RBAC role or access policy | Assign `Key Vault Secrets User` role; or add access policy with `get` permission |
| "Vault not found" | Network access restricted | Check firewall rules; enable private endpoint; add IP to allow list |
| Soft-deleted secret blocks creation | Name collision with deleted secret | Recover and update, or purge the deleted secret first |
| Managed identity cannot access vault | Identity not in correct scope | Verify identity principal ID; check role assignment scope matches vault |
| Certificate renewal fails | Auto-renew policy not configured | Set `lifetimeActions` with `AutoRenew` action in certificate policy |
| CSI driver fails to mount secrets | Wrong provider configuration | Verify `tenantId` , `userAssignedIdentityID` , and object names match exactly |
| High latency on secret retrieval | No client-side caching | Implement caching in application; use CSI driver for K8s (syncs on interval) |
2026-01-27 17:35:45 -05:00
## Best Practices
2026-03-24 18:02:50 -04:00
- Use RBAC authorization over access policies for granular control
- Enable soft-delete and purge protection (required for compliance)
- Use managed identities for all service access (no credentials to manage)
- Enable private endpoints to eliminate public network exposure
- Set expiration dates on all secrets and certificates
- Enable diagnostic logging and forward to SIEM
- Use premium SKU for HSM-backed key operations
- Implement key rotation policies for all encryption keys
- Regularly audit access with Azure Activity logs
- Tag all vault resources for cost and ownership tracking
2026-01-27 17:35:45 -05:00
## Related Skills
- [hashicorp-vault ](../hashicorp-vault/ ) - Multi-cloud secrets
- [azure-networking ](../../../infrastructure/cloud-azure/azure-networking/ ) - Network security
2026-03-24 18:02:50 -04:00
- [aws-secrets-manager ](../aws-secrets-manager/ ) - AWS secret management
- [gcp-secret-manager ](../gcp-secret-manager/ ) - GCP secret management