Azure

Azure Key Vault: Securing Your Application Secrets

Azure Key Vault: Securing Your Application Secrets

  • Azure subscription (free trial available)
  • Azure CLI version 2.40 or later
  • Basic understanding of Azure Active Directory (now Microsoft Entra ID)
  • An application or service that needs to store secrets (we'll use a simple example)
  • Contributor or Key Vault Contributor role on production

Overview

In this guide, you'll create an Azure Key Vault, store various types of secrets, implement secure access patterns using managed identities, and integrate Key Vault with a Node.js application. We'll cover:

Overview

  1. Creating and configuring Azure Key Vault
  2. Storing secrets, keys, and certificates
  3. Implementing secure access with managed identities
  4. Integrating Key Vault with applications
  5. Monitoring and auditing secret access
  6. Production-ready security patterns

Figure: Decision matrix mapping secret types (API keys, connection strings, encryption keys, certificates) to retrieval patterns (per-request, startup prefetch, scheduled rotation) and enforcement controls (RBAC, purge protection, private endpoint). Embedded early to contextualize architectural trade-offs before deep implementation.

Architecture Overview

$Expiry = [DateTime]$Secret.attributes.expires
if ((($Expiry - (Get-Date)).TotalDays) -lt $ThresholdDays) {
Write-Host "Rotating $SecretName"
$NewValue = (New-Guid).Guid.Replace('-', '').Substring(0,32)
az keyvault secret set --vault-name $VaultName --name $SecretName --value $NewValue --expires $((Get-Date).AddMonths(12).ToString('s')+'Z') | Out-Null
}

Architecture Overview


Key rotation via Bicep module (using verified AVM module):

```bicep
module kv 'br/public:avm/res/key-vault/vault:<version>' = {
  name: 'kvEnterprise'
  params: {
```yaml
name: 'kv-enterprise-prod'
enablePurgeProtection: true
enableRbacAuthorization: true
keys: [
  {
    name: 'encKey'
    rotationPolicy: {
      attributes: {
        expiryTime: 'P2Y'
      }
      lifetimeActions: [
        {
          action: { type: 'rotate' }
          trigger: { timeBeforeExpiry: 'P30D' }
        }
        {
          action: { type: 'notify' }
          trigger: { timeBeforeExpiry: 'P60D' }
        }
      ]
    }
  }
]```
  }
}

Performance & Caching Strategies

Concern Symptom Strategy Notes
Latency Repeated secret fetch calls In-memory cache (TTL) Avoid long TTL > rotation cycle
Startup Delay Cold start needs many secrets Batch fetch asynchronously Parallelize when safe
Throttling 429 responses from vault Exponential backoff + jitter Monitor metrics for sustained 429s
Regional Resilience Higher latency cross-region Prefer local vault per region Sync secrets via pipeline, not app
Large Secret Payloads Increased transfer time Keep secrets small (config → App Config) Separate config vs sensitive values

Performance & Caching Strategies

Example Node.js cache wrapper:

class SecretCache {
  constructor(client, ttlMs = 300000) { // 5 min default
```text
this.client = client; this.ttlMs = ttlMs; this.store = new Map();```
  }


_Figure: Application runtime flow—managed identity authentication, first secret fetch populating cache, subsequent requests served locally until TTL expires, with rotation invalidation path. Reinforces performance & caching strategies in this section._
  async get(name) {
```javascript
const entry = this.store.get(name);
const now = Date.now();
if (entry && (now - entry.ts) < this.ttlMs) return entry.value;
const secret = await this.client.getSecret(name);
this.store.set(name, { value: secret.value, ts: now });
return secret.value;```
  }
}

Observability & Auditing Enhancements

Kusto queries:

Observability & Auditing Enhancements

AzureDiagnostics
| where ResourceType == 'VAULTS'
| summarize count() by OperationName
AzureDiagnostics
| where OperationName == 'SecretGet'
| summarize requests = count() by identity_claim_upn_s
| order by requests desc

Alert Strategy:

  • Spike in SecretGet operations for single identity.
  • Unexpected operations (e.g., purge attempts) outside maintenance window.
  • Approaching secret expiry (< 14 days) without rotation event.

Resilience & Disaster Recovery

Risk Mitigation Detail
Accidental deletion Soft delete + purge protection Mandatory for production
Regional outage Multiple vaults (active-active) Deploy per region + pipeline sync
Compromised secret Immediate version rollback Re-point apps to previous version
Access escalation Principle of least privilege reviews Quarterly RBAC audit
Network isolation failure Private endpoint + deny public Policy enforcement

Resilience & Disaster Recovery

Rotation rollback pattern:

  1. Detect failure (app telemetry errors after deploy).
  2. Fetch prior secret version ID.
  3. Promote previous version by updating reference (env variable / config store).
  4. Trigger targeted app restart.

Troubleshooting Matrix (Extended)

Symptom Root Cause Diagnosis Resolution
High latency (p95 > 200ms) Excessive per-request secret fetch App Insights dependency traces Implement TTL caching layer
Frequent 401 on secret reads Managed identity token failure Identity logs / AzureDiagnostics Reassign role; check identity state
Rotation script fails silently Missing Function permissions Function app role assignments Grant Secrets Officer to function identity
Unauthorized purge attempt Malicious / misconfigured principal AuditEvent logs Review RBAC; disable access; alert SOC
Expired certificate not auto-renewed CA integration misconfigured Certificate status in portal Re-import with correct policy
Inconsistent secrets across regions Manual sync oversight Compare versions via CLI Automate sync in pipeline

Troubleshooting Matrix (Extended)

Image References

Image References

Step-by-Step Guide

Step 1: Create an Azure Key Vault

Step-by-Step Guide

First, set up a resource group and Key Vault:

## Set variables for reusability
$RESOURCE_GROUP="rg-keyvault-demo"
$LOCATION="eastus"
$KEY_VAULT_NAME="kv-secure-app-$((Get-Random -Maximum 9999))"

![Set variables for reusability](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec9-config.jpg)


## Create resource group
az group create --name $RESOURCE_GROUP --location $LOCATION

![Create resource group](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec10-implementation.jpg)


## Create Key Vault with RBAC authorization (recommended over access policies)
az keyvault create `
  --name $KEY_VAULT_NAME `
  --resource-group $RESOURCE_GROUP `
  --location $LOCATION `
  --enable-rbac-authorization true `
  --enabled-for-deployment false `
  --enabled-for-disk-encryption false `
  --enabled-for-template-deployment false

![Create Key Vault with RBAC authorization (recommended over access policies)](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec11-implementation.jpg)


## Get your user object ID
$USER_OBJECT_ID = az ad signed-in-user show --query id -o tsv

![Get your user object ID](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec12-generic.jpg)


## Grant yourself Key Vault Secrets Officer role
az role assignment create `
  --role "Key Vault Secrets Officer" `
  --assignee $USER_OBJECT_ID `
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.KeyVault/vaults/$KEY_VAULT_NAME"

![Grant yourself Key Vault Secrets Officer role](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec13-generic.jpg)

Expected output:

{ "name": "rg-myapp-prod", "location": "eastus2", "properties": { "provisioningState": "Succeeded" } }

Terminal output for az group create

Important Configuration Choices:

  • RBAC Authorization: Modern, recommended approach for access control
  • Deployment Flags: Disabled for security (enable only if needed)
  • Soft Delete: Enabled by default (retains deleted secrets for 90 days)
  • Purge Protection: Consider enabling for production to prevent permanent deletion

Step 2: Store Secrets in Key Vault

Add different types of secrets:

Step 2: Store Secrets in Key Vault

## Store a database connection string
az keyvault secret set `
  --vault-name $KEY_VAULT_NAME `
  --name "DatabaseConnectionString" `
  --value "Server=myserver.database.windows.net;Database=mydb;User Id=admin;Password=SecureP@ssw0rd!"

![Store a database connection string](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec15-database.jpg)


## Store an API key with expiration
$EXPIRY_DATE = (Get-Date).AddYears(1).ToString("yyyy-MM-ddTHH:mm:ssZ")
az keyvault secret set `
  --vault-name $KEY_VAULT_NAME `
  --name "ThirdPartyApiKey" `
  --value "sk_live_51H..." `
  --expires $EXPIRY_DATE

![Store an API key with expiration](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec16-api.jpg)


## Store a certificate (upload from file)
az keyvault certificate import `
  --vault-name $KEY_VAULT_NAME `
  --name "AppServiceCertificate" `
  --file "path/to/certificate.pfx" `
  --password "cert-password"

![Store a certificate (upload from file)](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec17-storage.jpg)


## Create a cryptographic key for encryption
az keyvault key create `
  --vault-name $KEY_VAULT_NAME `
  --name "DataEncryptionKey" `
  --kty RSA `
  --size 2048 `
  --ops encrypt decrypt

![Create a cryptographic key for encryption](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec18-implementation.jpg)

Expected output:

{ "id": "https://kv-myapp.vault.azure.net/secrets/MySecret/abc123", "attributes": { "enabled": true } }

Terminal output for az keyvault secret set

Retrieve a secret to verify:

## Get secret value
az keyvault secret show `
  --vault-name $KEY_VAULT_NAME `
  --name "DatabaseConnectionString" `
  --query "value" -o tsv

![Get secret value](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec19-generic.jpg)

Step 3: Implement Managed Identity Access

Create a managed identity for secure, password-less authentication:

Step 3: Implement Managed Identity Access

## Create a user-assigned managed identity
$IDENTITY_NAME="id-secure-app"
az identity create `
  --name $IDENTITY_NAME `
  --resource-group $RESOURCE_GROUP `
  --location $LOCATION

![Create a user-assigned managed identity](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec21-implementation.jpg)


## Get the identity's principal ID
$IDENTITY_PRINCIPAL_ID = az identity show `
  --name $IDENTITY_NAME `
  --resource-group $RESOURCE_GROUP `
  --query principalId -o tsv

![Get the identity's principal ID](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec22-security.jpg)


## Grant the identity read access to secrets
az role assignment create `
  --role "Key Vault Secrets User" `
  --assignee $IDENTITY_PRINCIPAL_ID `
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.KeyVault/vaults/$KEY_VAULT_NAME"

![Grant the identity read access to secrets](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec23-security.jpg)

Expected output:

{ "roleDefinitionName": "Key Vault Secrets Officer", "scope": "/subscriptions/xxxxxxxx/resourceGroups/rg-myapp" }

Terminal output for az role assignment create

For Azure services (App Service, Functions, VMs), enable system-assigned identity:

## Example: Enable managed identity on an App Service
az webapp identity assign `
  --name "my-app-service" `
  --resource-group $RESOURCE_GROUP

![Example: Enable managed identity on an App Service](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec24-security.jpg)


## Then grant it Key Vault access using the same role assignment pattern

Then grant it Key Vault access using the same role assignment pattern

Step 4: Integrate Key Vault with Your Application

Here's how to access Key Vault from a Node.js application using managed identity:

Step 4: Integrate Key Vault with Your Application

Install dependencies:

npm install @azure/keyvault-secrets @azure/identity

Expected output:

added 245 packages in 8s
found 0 vulnerabilities

Terminal output for npm install

Application code:

const { SecretClient } = require("@azure/keyvault-secrets");
const { DefaultAzureCredential } = require("@azure/identity");

async function getSecret(secretName) {
```javascript
try {
    // DefaultAzureCredential automatically uses managed identity in Azure
    // and falls back to Azure CLI credentials locally
    const credential = new DefaultAzureCredential();
    
    const vaultUrl = `https://${process.env.KEY_VAULT_NAME}.vault.azure.net`;
    const client = new SecretClient(vaultUrl, credential);
    
    // Retrieve the secret
    const secret = await client.getSecret(secretName);
    console.log(`Retrieved secret: ${secretName}`);
    
    return secret.value;
} catch (error) {
    console.error(`Error retrieving secret: ${error.message}`);
    throw error;
}```
}

async function main() {
```javascript
// Example: Get database connection string
const dbConnectionString = await getSecret("DatabaseConnectionString");

// Use the secret (never log the actual value!)
console.log("Successfully retrieved database connection");

// Example: Get API key
const apiKey = await getSecret("ThirdPartyApiKey");

// Use secrets in your application
// initializeDatabase(dbConnectionString);
// configureApiClient(apiKey);```
}

main().catch(error => {
```text
console.error("Application error:", error);
process.exit(1);```
});

Set environment variable:

## Locally (for development)
$env:KEY_VAULT_NAME="kv-secure-app-1234"

![Locally (for development)](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec27-implementation.jpg)


## In Azure App Service (production)
az webapp config appsettings set `
  --name "my-app-service" `
  --resource-group $RESOURCE_GROUP `
  --settings KEY_VAULT_NAME="kv-secure-app-1234"

![In Azure App Service (production)](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec28-advanced.jpg)

Step 5: Enable Monitoring and Auditing

Configure diagnostic settings to track secret access:

Step 5: Enable Monitoring and Auditing

## Create a Log Analytics workspace
az monitor log-analytics workspace create `
  --workspace-name "law-keyvault-audit" `
  --resource-group $RESOURCE_GROUP `
  --location $LOCATION

![Create a Log Analytics workspace](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec30-implementation.jpg)


## Get workspace ID
$WORKSPACE_ID = az monitor log-analytics workspace show `
  --workspace-name "law-keyvault-audit" `
  --resource-group $RESOURCE_GROUP `
  --query id -o tsv

![Get workspace ID](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec31-generic.jpg)


## Enable diagnostic logging
az monitor diagnostic-settings create `
  --name "KeyVaultAuditLogs" `
  --resource "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.KeyVault/vaults/$KEY_VAULT_NAME" `
  --workspace $WORKSPACE_ID `
  --logs '[{"category": "AuditEvent", "enabled": true}]' `
  --metrics '[{"category": "AllMetrics", "enabled": true}]'

![Enable diagnostic logging](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec32-monitoring.jpg)

Expected output:

{ "value": [{ "name": { "value": "Requests" }, "timeseries": [{ "data": [{ "total": 1234 }] }] }] }

Terminal output for az monitor

Query audit logs:

// Run in Log Analytics workspace
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName == "SecretGet"
| project TimeGenerated, CallerIPAddress, identity_claim_upn_s, requestUri_s
| order by TimeGenerated desc

Step 6: Implement Secret Rotation

Automate secret rotation using Azure Key Vault rotation policy:

Step 6: Implement Secret Rotation

## Set rotation policy for a secret (90-day rotation)
az keyvault secret set-attributes `
  --vault-name $KEY_VAULT_NAME `
  --name "ThirdPartyApiKey" `
  --expires $EXPIRY_DATE

![Set rotation policy for a secret (90-day rotation)](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec34-governance.jpg)


## For automated rotation, use Azure Functions or Logic Apps

![For automated rotation, use Azure Functions or Logic Apps](/images/articles/azure/2025-01-27-azure-key-vault-securing-your-application-secrets-sec35-monitoring.jpg)

## Trigger rotation based on expiry notifications

Expected output:

{ "id": "https://kv-myapp.vault.azure.net/secrets/MySecret/abc123", "attributes": { "enabled": true } }

Terminal output for az keyvault secret set

Trigger rotation based on expiry notifications

Best practice pattern:

  1. Store both current and previous secret versions
  2. Update applications to use new secrets
  3. Deprecate old secrets after grace period
  4. Monitor for applications still using old versions

Best Practices

  • Use Managed Identities: Never store Key Vault credentials in code or configuration files. Always use managed identities for Azure-hosted applications and service principals with minimal permissions for external services.

Best Practices

  • Implement Least Privilege: Grant only the specific permissions needed (e.g., "Key Vault Secrets User" for read-only access). Avoid broad roles like "Key Vault Administrator" for application identities.

  • Enable Soft Delete and Purge Protection: Protect against accidental or malicious deletion. Soft delete retains secrets for 90 days; purge protection prevents permanent deletion during that period.

  • Separate Key Vaults by Environment: Use different Key Vaults for dev, test, and production. This isolation prevents cross-environment secret leaks and simplifies access management.

  • Implement Secret Versioning: Key Vault maintains secret versions automatically. Reference specific versions in production; use "latest" cautiously and only after thorough testing.

  • Monitor and Alert: Configure alerts for unusual access patterns, failed authentication attempts, or secret expirations. Use Azure Monitor and Log Analytics for comprehensive auditing.

  • Rotate Secrets Regularly: Establish rotation policies (30-90 days for highly sensitive secrets). Automate rotation where possible using Azure Functions or Key Vault rotation features.

  • Use Network Restrictions: Configure firewall rules and private endpoints to limit Key Vault access to specific networks. Disable public access for production Key Vaults when possible.

Common Issues & Troubleshooting

Issue: The user, group or application does not have secrets get permission
Solution: Verify RBAC role assignments using az role assignment list --scope <key-vault-resource-id>. Ensure the identity has "Key Vault Secrets User" or higher role. Role propagation can take 5-10 minutes after assignment.

Common Issues & Troubleshooting

Issue: DefaultAzureCredential failed to retrieve a token when running locally
Solution: Ensure you're logged into Azure CLI (az login). For managed identity to work locally, the CLI credentials are used as a fallback. In production, verify the managed identity is enabled and has proper role assignments.

Issue: Secrets not accessible from Azure App Service
Solution: 1) Verify managed identity is enabled on the App Service. 2) Check the identity has appropriate Key Vault role assignments. 3) Ensure firewall rules allow App Service outbound IP addresses if network restrictions are configured. 4) Verify the Key Vault URL is correct in application settings.

Issue: Certificate import fails with parsing error
Solution: Ensure the certificate is in PFX/PKCS12 format with a password. PEM files need conversion first. Verify the certificate chain is complete and the password is correct.

Architecture Decision and Tradeoffs

When designing cloud infrastructure solutions with Azure, consider these key architectural trade-offs:

Approach Best For Tradeoff
Managed / platform service Rapid delivery, reduced ops burden Less customisation, potential vendor lock-in
Custom / self-hosted Full control, advanced tuning Higher operational overhead and cost

Recommendation: Start with the managed approach for most workloads and move to custom only when specific requirements demand it.

Validation and Versioning

  • Last validated: April 2026
  • Validate examples against your tenant, region, and SKU constraints before production rollout.
  • Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.

Security and Governance Considerations

  • Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
  • Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
  • Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.

Cost and Performance Notes

  • Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
  • Baseline performance with synthetic and real-user checks before and after major changes.
  • Scale resources with measured thresholds and revisit sizing after usage pattern changes.

Official Microsoft References

Public Examples from Official Sources

Key Takeaways

  • ✅ Azure Key Vault centralizes secret management, eliminating hardcoded credentials and secret sprawl
  • ✅ Managed identities provide secure, password-less authentication between Azure services
  • ✅ RBAC-based access control offers fine-grained permissions aligned with zero-trust principles
  • ✅ Comprehensive audit logging tracks all secret access for compliance and security monitoring
  • ✅ Built-in features like soft delete, versioning, and rotation policies protect against common security pitfalls

Key Takeaways

Next Steps

Additional Resources


How are you managing secrets in your applications? Have you implemented Key Vault? Share your security journey and questions below!
```

AI Assistant
AI Assistant

Article Assistant

Ask me about this article

AI
Hi! I'm here to help you understand this article. Ask me anything about the content, concepts, or implementation details.