Azure Key Vault: Complete Secrets Management Guide
Azure Key Vault provides secure storage and management of secrets, keys, and certificates. This comprehensive guide covers everything from basic setup to advanced security configurations for small business environments.
Understanding Azure Key Vault
Key Vault Objects
- Secrets: Application secrets, passwords, connection strings
- Keys: Cryptographic keys for encryption and signing
- Certificates: SSL/TLS certificates and PKI management
- Storage Account Keys: Automated key rotation
Pricing Tiers
- Standard: Software-protected keys and secrets
- Premium: Hardware Security Module (HSM) protected keys
- Managed HSM: Dedicated HSM instances
Creating and Configuring Key Vault
PowerShell Setup
# Install Azure PowerShell module
Install-Module -Name Az -Force
# Connect to Azure
Connect-AzAccount
# Create resource group
New-AzResourceGroup -Name "KeyVault-RG" -Location "East US"
# Create Key Vault
$vault = New-AzKeyVault `
-ResourceGroupName "KeyVault-RG" `
-VaultName "BusinessKeyVault001" `
-Location "East US" `
-EnabledForDeployment `
-EnabledForTemplateDeployment `
-EnabledForDiskEncryption `
-Sku "Standard"
# Enable soft delete and purge protection
Update-AzKeyVault `
-ResourceGroupName "KeyVault-RG" `
-VaultName "BusinessKeyVault001" `
-EnableSoftDelete `
-EnablePurgeProtection
Azure CLI Setup
# Login to Azure
az login
# Create resource group
az group create --name "KeyVault-RG" --location "eastus"
# Create Key Vault
az keyvault create \
--name "BusinessKeyVault001" \
--resource-group "KeyVault-RG" \
--location "eastus" \
--enable-soft-delete \
--enable-purge-protection \
--enabled-for-deployment \
--enabled-for-template-deployment \
--enabled-for-disk-encryption
Access Control and Security
Access Policies
# Set access policy for user
Set-AzKeyVaultAccessPolicy `
-VaultName "BusinessKeyVault001" `
-UserPrincipalName "admin@company.com" `
-PermissionsToSecrets get,list,set,delete `
-PermissionsToKeys get,list,create,delete,update `
-PermissionsToCertificates get,list,create,delete,update
# Set access policy for service principal
Set-AzKeyVaultAccessPolicy `
-VaultName "BusinessKeyVault001" `
-ServicePrincipalName "12345678-1234-1234-1234-123456789012" `
-PermissionsToSecrets get,list `
-PermissionsToKeys get,list
RBAC Integration
# Enable RBAC for Key Vault
Update-AzKeyVault `
-ResourceGroupName "KeyVault-RG" `
-VaultName "BusinessKeyVault001" `
-EnableRbacAuthorization
# Assign RBAC roles
New-AzRoleAssignment `
-SignInName "admin@company.com" `
-RoleDefinitionName "Key Vault Secrets Officer" `
-Scope "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001"
New-AzRoleAssignment `
-SignInName "developer@company.com" `
-RoleDefinitionName "Key Vault Secrets User" `
-Scope "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001"
Network Security
# Configure network access rules
Update-AzKeyVault `
-ResourceGroupName "KeyVault-RG" `
-VaultName "BusinessKeyVault001" `
-DefaultAction "Deny" `
-NetworkRuleSet @{
"ipRules" = @(
@{
"ipAddressOrRange" = "203.0.113.0/24"
"action" = "Allow"
}
)
"virtualNetworkRules" = @(
@{
"virtualNetworkResourceId" = "/subscriptions/subscription-id/resourceGroups/Network-RG/providers/Microsoft.Network/virtualNetworks/Business-VNet/subnets/KeyVault-Subnet"
"action" = "Allow"
}
)
}
Secrets Management
Creating and Managing Secrets
# Create secret
Set-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString" `
-SecretValue (ConvertTo-SecureString "Server=businesssqlserver001.database.windows.net;Database=BusinessDB;User Id=sqladmin;Password=SecurePassword123!;" -AsPlainText -Force)
# Create secret with expiration
Set-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "APIKey" `
-SecretValue (ConvertTo-SecureString "api-key-value" -AsPlainText -Force) `
-Expires (Get-Date).AddYears(1) `
-ContentType "text/plain"
# Get secret
$secret = Get-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString"
# Get secret value
$secretValue = Get-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString" `
-AsPlainText
Secret Versioning
# Update secret (creates new version)
Set-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString" `
-SecretValue (ConvertTo-SecureString "Server=businesssqlserver001.database.windows.net;Database=BusinessDB;User Id=sqladmin;Password=NewSecurePassword123!;" -AsPlainText -Force)
# List secret versions
Get-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString" `
-IncludeVersions
# Get specific version
Get-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name "DatabaseConnectionString" `
-Version "12345678123456781234567812345678" `
-AsPlainText
Bulk Secret Operations
# Import secrets from JSON file
$secrets = @{
"SMTPPassword" = "smtp-password"
"StorageAccountKey" = "storage-account-key"
"ThirdPartyAPIKey" = "third-party-api-key"
}
foreach ($secretName in $secrets.Keys) {
Set-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name $secretName `
-SecretValue (ConvertTo-SecureString $secrets[$secretName] -AsPlainText -Force)
}
# Export secrets (for backup/migration)
$allSecrets = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001"
$secretsBackup = @{}
foreach ($secret in $allSecrets) {
$secretValue = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -Name $secret.Name -AsPlainText
$secretsBackup[$secret.Name] = $secretValue
}
$secretsBackup | ConvertTo-Json | Out-File "secrets-backup.json"
Key Management
Creating Cryptographic Keys
# Create RSA key
Add-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "EncryptionKey" `
-KeyType "RSA" `
-KeySize 2048 `
-KeyUsage "Encrypt", "Decrypt"
# Create EC key
Add-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "SigningKey" `
-KeyType "EC" `
-CurveName "P-256" `
-KeyUsage "Sign", "Verify"
# Create HSM-protected key (Premium tier)
Add-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "HSMKey" `
-KeyType "RSA-HSM" `
-KeySize 2048 `
-KeyUsage "Encrypt", "Decrypt"
Key Operations
# Get key
$key = Get-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "EncryptionKey"
# Encrypt data
$plaintext = "sensitive data"
$plaintextBytes = [System.Text.Encoding]::UTF8.GetBytes($plaintext)
$encryptedData = Invoke-AzKeyVaultKeyOperation `
-VaultName "BusinessKeyVault001" `
-KeyName "EncryptionKey" `
-Operation "Encrypt" `
-Algorithm "RSA-OAEP" `
-Value $plaintextBytes
# Decrypt data
$decryptedData = Invoke-AzKeyVaultKeyOperation `
-VaultName "BusinessKeyVault001" `
-KeyName "EncryptionKey" `
-Operation "Decrypt" `
-Algorithm "RSA-OAEP" `
-Value $encryptedData.Result
$decryptedText = [System.Text.Encoding]::UTF8.GetString($decryptedData.Result)
Key Rotation
# Create new key version
Add-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "EncryptionKey" `
-KeyType "RSA" `
-KeySize 2048 `
-KeyUsage "Encrypt", "Decrypt"
# Set key expiration
Update-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "EncryptionKey" `
-Expires (Get-Date).AddMonths(6)
# Disable old key version
Update-AzKeyVaultKey `
-VaultName "BusinessKeyVault001" `
-Name "EncryptionKey" `
-Version "old-version-id" `
-Enable $false
Certificate Management
Creating Self-Signed Certificates
# Create certificate policy
$policy = New-AzKeyVaultCertificatePolicy `
-SubjectName "CN=company.com" `
-IssuerName "Self" `
-ValidityInMonths 12 `
-RenewAtNumberOfDaysBeforeExpiry 30
# Create certificate
Add-AzKeyVaultCertificate `
-VaultName "BusinessKeyVault001" `
-Name "CompanyCertificate" `
-CertificatePolicy $policy
Importing Certificates
# Import PFX certificate
Import-AzKeyVaultCertificate `
-VaultName "BusinessKeyVault001" `
-Name "SSLCertificate" `
-FilePath "C:\Certificates\ssl-certificate.pfx" `
-Password (ConvertTo-SecureString "certificate-password" -AsPlainText -Force)
# Import certificate from file
$cert = Import-AzKeyVaultCertificate `
-VaultName "BusinessKeyVault001" `
-Name "CACertificate" `
-FilePath "C:\Certificates\ca-certificate.cer"
Certificate Automation
# Set up Let's Encrypt certificate
$policy = New-AzKeyVaultCertificatePolicy `
-SubjectName "CN=www.company.com" `
-IssuerName "Let's Encrypt" `
-ValidityInMonths 3 `
-RenewAtNumberOfDaysBeforeExpiry 30 `
-SubjectAlternativeNames @("company.com", "api.company.com")
Add-AzKeyVaultCertificate `
-VaultName "BusinessKeyVault001" `
-Name "LetsEncryptCertificate" `
-CertificatePolicy $policy
Application Integration
.NET Integration
// Install NuGet packages:
// Azure.Security.KeyVault.Secrets
// Azure.Identity
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
public class KeyVaultService
{
private readonly SecretClient _secretClient;
public KeyVaultService()
{
var credential = new DefaultAzureCredential();
_secretClient = new SecretClient(
new Uri("https://businesskeyvault001.vault.azure.net/"),
credential);
}
public async Task<string> GetSecretAsync(string secretName)
{
try
{
var secret = await _secretClient.GetSecretAsync(secretName);
return secret.Value.Value;
}
catch (Exception ex)
{
// Handle exception
throw;
}
}
public async Task SetSecretAsync(string secretName, string secretValue)
{
await _secretClient.SetSecretAsync(secretName, secretValue);
}
}
PowerShell Integration
# Function to get secret
function Get-BusinessSecret {
param(
[string]$SecretName,
[string]$VaultName = "BusinessKeyVault001"
)
try {
$secret = Get-AzKeyVaultSecret -VaultName $VaultName -Name $SecretName -AsPlainText
return $secret
}
catch {
Write-Error "Failed to retrieve secret: $($_.Exception.Message)"
return $null
}
}
# Function to set secret
function Set-BusinessSecret {
param(
[string]$SecretName,
[string]$SecretValue,
[string]$VaultName = "BusinessKeyVault001"
)
try {
Set-AzKeyVaultSecret -VaultName $VaultName -Name $SecretName -SecretValue (ConvertTo-SecureString $SecretValue -AsPlainText -Force)
Write-Host "Secret '$SecretName' set successfully"
}
catch {
Write-Error "Failed to set secret: $($_.Exception.Message)"
}
}
ARM Template Integration
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"defaultValue": "BusinessKeyVault001"
}
},
"variables": {},
"resources": [
{
"type": "Microsoft.Web/sites",
"apiVersion": "2021-02-01",
"name": "businesswebapp001",
"properties": {
"siteConfig": {
"appSettings": [
{
"name": "DatabaseConnectionString",
"value": "[concat('@Microsoft.KeyVault(SecretUri=https://', parameters('keyVaultName'), '.vault.azure.net/secrets/DatabaseConnectionString/)')]"
}
]
}
}
}
]
}
Monitoring and Auditing
Diagnostic Settings
# Enable diagnostic logging
$workspaceId = "/subscriptions/subscription-id/resourceGroups/Monitoring-RG/providers/Microsoft.OperationalInsights/workspaces/BusinessLogAnalytics"
Set-AzDiagnosticSetting `
-ResourceId "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001" `
-Name "KeyVaultDiagnostics" `
-Enabled $true `
-WorkspaceId $workspaceId `
-Log @(
@{
"category" = "AuditEvent"
"enabled" = $true
"retentionPolicy" = @{
"enabled" = $true
"days" = 90
}
}
)
Azure Monitor Alerts
# Create action group
$actionGroup = New-AzActionGroup `
-ResourceGroupName "KeyVault-RG" `
-Name "keyvault-alerts" `
-ShortName "kvAlerts" `
-EmailReceiver @{
"name" = "admin"
"emailAddress" = "admin@company.com"
}
# Create alert rule for failed access attempts
New-AzMetricAlertRule `
-ResourceGroupName "KeyVault-RG" `
-Name "failed-key-vault-access" `
-TargetResourceId "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001" `
-MetricName "ServiceApiResult" `
-Operator "GreaterThan" `
-Threshold 5 `
-WindowSize "00:15:00" `
-TimeAggregationOperator "Total" `
-ActionGroupId $actionGroup.Id
Log Analytics Queries
// Key Vault access logs
KeyVaultLogs
| where TimeGenerated > ago(24h)
| where ResultType != "Success"
| summarize count() by CallerIPAddress, OperationName
| order by count_ desc
// Secret access patterns
KeyVaultLogs
| where TimeGenerated > ago(7d)
| where OperationName == "SecretGet"
| summarize count() by SecretName = tostring(parse_json(Properties).secretName)
| order by count_ desc
// Certificate expiration monitoring
KeyVaultLogs
| where TimeGenerated > ago(30d)
| where OperationName == "CertificateGet"
| extend CertName = tostring(parse_json(Properties).certificateName)
| summarize LastAccessed = max(TimeGenerated) by CertName
Backup and Recovery
Backup Strategies
# Backup all secrets
$secrets = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001"
$backup = @{}
foreach ($secret in $secrets) {
$secretValue = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -Name $secret.Name -AsPlainText
$backup[$secret.Name] = @{
"value" = $secretValue
"contentType" = $secret.ContentType
"expires" = $secret.Expires
"notBefore" = $secret.NotBefore
}
}
# Save backup
$backup | ConvertTo-Json -Depth 3 | Out-File "keyvault-backup-$(Get-Date -Format 'yyyyMMdd-HHmmss').json"
# Backup individual secret
$secretBackup = Backup-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -Name "DatabaseConnectionString" -OutputFile "secret-backup.blob"
Recovery Procedures
# Restore from backup file
Restore-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -InputFile "secret-backup.blob"
# Restore from JSON backup
$backupData = Get-Content "keyvault-backup.json" | ConvertFrom-Json
foreach ($secretName in $backupData.PSObject.Properties.Name) {
$secretInfo = $backupData.$secretName
Set-AzKeyVaultSecret `
-VaultName "BusinessKeyVault001" `
-Name $secretName `
-SecretValue (ConvertTo-SecureString $secretInfo.value -AsPlainText -Force) `
-ContentType $secretInfo.contentType `
-Expires $secretInfo.expires
}
Best Practices
Security
- Use RBAC instead of access policies when possible
- Enable soft delete and purge protection
- Implement network restrictions for production vaults
- Regular access reviews and permission audits
Operations
- Use managed identities for application access
- Implement secret rotation policies
- Monitor access patterns with Azure Monitor
- Backup critical secrets regularly
Development
- Use different vaults for different environments
- Implement proper error handling in applications
- Use Azure Key Vault references in ARM templates
- Test disaster recovery procedures
Cost Optimization
Usage Monitoring
# Monitor Key Vault operations
Get-AzMetric `
-ResourceId "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001" `
-MetricName "ServiceApiHit" `
-TimeGrain 01:00:00 `
-StartTime (Get-Date).AddDays(-30) `
-EndTime (Get-Date)
# Calculate monthly costs
$operations = 10000 # Example operations per month
$standardCost = [math]::Ceiling($operations / 10000) * 0.03
$premiumCost = [math]::Ceiling($operations / 10000) * 0.15
Write-Host "Standard tier monthly cost: $${standardCost}"
Write-Host "Premium tier monthly cost: $${premiumCost}"
Optimization Strategies
# Cleanup old secret versions
$secrets = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001"
foreach ($secret in $secrets) {
$versions = Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -Name $secret.Name -IncludeVersions
$oldVersions = $versions | Where-Object { $_.Enabled -eq $false -and $_.Created -lt (Get-Date).AddDays(-30) }
foreach ($oldVersion in $oldVersions) {
Remove-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -Name $secret.Name -Version $oldVersion.Version -Force
}
}
Troubleshooting
Common Issues
# Check vault status
Get-AzKeyVault -VaultName "BusinessKeyVault001"
# Test connectivity
Test-AzKeyVaultKeyOperation -VaultName "BusinessKeyVault001" -KeyName "TestKey"
# Check access permissions
Get-AzKeyVaultAccessPolicy -VaultName "BusinessKeyVault001"
# Verify network access
$context = Get-AzContext
Invoke-AzRestMethod -Uri "https://businesskeyvault001.vault.azure.net/secrets?api-version=7.3" -Method GET
Error Resolution
# Access denied errors
# Check RBAC assignments
Get-AzRoleAssignment -Scope "/subscriptions/subscription-id/resourceGroups/KeyVault-RG/providers/Microsoft.KeyVault/vaults/BusinessKeyVault001"
# Network access errors
# Check firewall rules
Get-AzKeyVault -VaultName "BusinessKeyVault001" | Select-Object -ExpandProperty NetworkRuleSet
# Soft delete recovery
# List deleted secrets
Get-AzKeyVaultSecret -VaultName "BusinessKeyVault001" -InRemovedState
# Recover deleted secret
Undo-AzKeyVaultSecretRemoval -VaultName "BusinessKeyVault001" -Name "DeletedSecret"
Conclusion
Azure Key Vault provides enterprise-grade security for managing secrets, keys, and certificates. Proper implementation of access controls, monitoring, and backup strategies ensures secure and reliable secret management for your business applications.
For professional Azure Key Vault implementation and security consulting services in Louisville, contact Tyler on Tech Louisville for expert assistance with your secrets management strategy.