security/secrets/azure-keyvault/SKILL.md
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.
npx skillsauth add bagelhole/devops-security-agent-skills azure-keyvaultInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Securely store and manage secrets, keys, and certificates in Azure.
Use this skill when:
az command)# Create a resource group
az group create --name rg-secrets --location eastus
# 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
# 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
# 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}}]'
# 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
# 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"}
}'
# 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
# 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 "[email protected]" \
--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)
# 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
from azure.identity import DefaultAzureCredential, ManagedIdentityCredential
from azure.keyvault.secrets import SecretClient
from azure.keyvault.keys import KeyClient
from azure.keyvault.certificates import CertificateClient
# Use DefaultAzureCredential (works locally and in Azure)
credential = DefaultAzureCredential()
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)
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;
# SecretProviderClass for AKS with managed identity
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-keyvault-secrets
namespace: production
spec:
provider: azure
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "<managed-identity-client-id>"
keyvaultName: "myapp-vault-prod"
cloudName: ""
objects: |
array:
- |
objectName: db-password
objectType: secret
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"
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
}
| 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) |
development
Design and operationalize SRE dashboards that surface reliability, latency, error, saturation, and capacity signals across services. Use when building observability views for SLOs, incident response, and executive reliability reporting.
testing
Harden OpenClaw self-hosted environments with baseline host controls, auth tightening, secret handling, network segmentation, and safe update/rollback workflows. Use when deploying OpenClaw in home labs, startups, or production-like local AI infrastructure.
devops
Deploy, manage, and optimize vector databases for AI applications. Covers Qdrant, Weaviate, pgvector, and Pinecone — collection management, indexing strategies, backup, and performance tuning for production RAG and semantic search workloads.
testing
Deploy ML models on Kubernetes with KServe (formerly KFServing) and NVIDIA Triton Inference Server. Includes canary deployments, autoscaling, model versioning, A/B testing, and GPU resource management for production model serving.