Azure Key Vault Integration
This guide covers the Azure Key Vault integration for TrustWeave. The Azure Key Vault plugin provides production-ready key management with support for Azure Key Vault-compatible algorithms.
Overview
The kms/plugins/azure module provides a complete implementation of TrustWeave’s KeyManagementService interface using Azure Key Vault. This integration enables you to:
- Use Azure Key Vault for secure key generation and storage
- Leverage Azure Key Vault’s key versioning and soft-delete capabilities
- Support Azure Key Vault-compatible algorithms (secp256k1, P-256/P-384/P-521, RSA)
- Integrate with existing Azure infrastructure and Managed Identity
- Meet regulatory compliance requirements with Azure’s security features
Installation
Add the Azure Key Vault module to your dependencies:
1
2
3
4
5
dependencies {
implementation("com.trustweave.kms:azure:1.0.0-SNAPSHOT")
implementation("com.trustweave:trustweave-kms:1.0.0-SNAPSHOT")
implementation("com.trustweave:trustweave-common:1.0.0-SNAPSHOT")
}
Configuration
Basic Configuration
The Azure Key Vault provider can be configured via options map or environment variables:
1
2
3
4
5
6
7
8
9
10
11
import com.trustweave.kms.*
import java.util.ServiceLoader
// Discover Azure provider
val providers = ServiceLoader.load(KeyManagementServiceProvider::class.java)
val azureProvider = providers.find { it.name == "azure" }
// Create KMS with explicit configuration
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://myvault.vault.azure.net"
))
Authentication
The plugin supports multiple authentication methods:
1. Managed Identity (Recommended for Production)
When running on Azure infrastructure (Azure VMs, App Service, Azure Functions, AKS), use Managed Identity:
1
2
3
4
// No credentials needed - uses Managed Identity automatically
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://myvault.vault.azure.net"
))
Enable Managed Identity on your Azure resource and grant it access to the Key Vault:
1
2
3
4
5
6
7
# Enable system-assigned managed identity
az vm identity assign --name my-vm --resource-group my-rg
# Grant access to Key Vault
az keyvault set-policy --name myvault \
--object-id <managed-identity-object-id> \
--key-permissions get list create sign verify
2. Service Principal
For local development or non-Azure environments:
1
2
3
4
5
6
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://myvault.vault.azure.net",
"clientId" to "client-id",
"clientSecret" to "client-secret",
"tenantId" to "tenant-id"
))
Create a service principal:
1
2
3
az ad sp create-for-rbac --name TrustWeave-kms \
--role "Key Vault Crypto Officer" \
--scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/vaults/{vault-name}
3. Environment Variables
The plugin automatically reads from environment variables:
1
2
3
4
export AZURE_VAULT_URL=https://myvault.vault.azure.net
export AZURE_CLIENT_ID=client-id
export AZURE_CLIENT_SECRET=client-secret
export AZURE_TENANT_ID=tenant-id
1
2
3
// Configuration loaded from environment automatically
val config = AzureKmsConfig.fromEnvironment()
val kms = AzureKeyManagementService(config ?: throw IllegalStateException("Azure config not found"))
Direct Configuration
You can also configure directly using the builder:
1
2
3
4
5
6
7
8
9
10
import com.trustweave.azurekms.*
val config = AzureKmsConfig.builder()
.vaultUrl("https://myvault.vault.azure.net")
.clientId("client-id")
.clientSecret("client-secret")
.tenantId("tenant-id")
.build()
val kms = AzureKeyManagementService(config)
Algorithm Support
The Azure Key Vault plugin supports the following algorithms:
| Algorithm | Azure Key Vault Key Type | Signing Algorithm | Notes |
|---|---|---|---|
| secp256k1 | EC with P-256K curve |
ES256K |
Blockchain-compatible |
| P-256 | EC with P-256 curve |
ES256 |
FIPS 140-2 compliant |
| P-384 | EC with P-384 curve |
ES384 |
FIPS 140-2 compliant |
| P-521 | EC with P-521 curve |
ES512 |
FIPS 140-2 compliant |
| RSA-2048 | RSA |
RS256 |
Legacy support |
| RSA-3072 | RSA |
RS256 |
Higher security |
| RSA-4096 | RSA |
RS256 |
Maximum security |
Note: Ed25519 is not directly supported by Azure Key Vault. Use P-256, P-384, or P-521 as alternatives.
Checking Algorithm Support
1
2
3
4
5
6
7
8
9
10
11
12
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://myvault.vault.azure.net"
))
// Get all supported algorithms
val supported = kms?.getSupportedAlgorithms()
println("Supported algorithms: ${supported?.joinToString { it.name }}")
// Check specific algorithm
if (kms?.supportsAlgorithm(Algorithm.P256) == true) {
println("P-256 is supported")
}
Usage Examples
Generating Keys
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import com.trustweave.kms.*
// Generate P-256 key
val key = kms.generateKey(Algorithm.P256)
// Generate key with custom name and tags
val keyWithTags = kms.generateKey(
algorithm = Algorithm.P256,
options = mapOf(
"keyName" to "issuer-key-2025",
"tags" to mapOf(
"environment" to "production",
"purpose" to "issuance"
),
"enabled" to true
)
)
// Generate P-256 key for FIPS compliance
val fipsKey = kms.generateKey(
algorithm = Algorithm.P256,
options = mapOf(
"keyName" to "fips-compliant-key"
)
)
Signing Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Sign with key name (KeyId value class)
val signature = kms.sign(KeyId(keyId), data.toByteArray())
// Sign with full key URL
val signature = kms.sign(
KeyId("https://myvault.vault.azure.net/keys/mykey"),
data.toByteArray()
)
// Sign with key name and version
val signature = kms.sign(
KeyId("mykey/abc123def456"),
data.toByteArray()
)
// Sign with algorithm override
val signature = kms.sign(
keyId = KeyId(keyId),
data = data.toByteArray(),
algorithm = Algorithm.P256
)
Retrieving Public Keys
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Get public key by key name (KeyId value class)
val publicKey = kms.getPublicKey(KeyId("mykey"))
// Get public key by full URL
val publicKey = kms.getPublicKey(
KeyId("https://myvault.vault.azure.net/keys/mykey")
)
// Get public key by name and version
val publicKey = kms.getPublicKey(KeyId("mykey/abc123def456"))
// Access JWK format
val jwk = publicKey.publicKeyJwk
println("Public key JWK: $jwk")
Key Deletion
1
2
3
4
5
6
// Schedule key deletion (soft delete)
val deleted = kms.deleteKey(KeyId(keyId))
// Note: Azure Key Vault uses soft delete by default
// Keys are recoverable for a retention period (default 90 days)
// To permanently delete, use Azure CLI or portal
Key Identifiers
Azure Key Vault supports multiple key identifier formats:
- Key name:
mykey(uses latest version) - Key name with version:
mykey/abc123def456 - Full URL:
https://myvault.vault.azure.net/keys/mykey - Full URL with version:
https://myvault.vault.azure.net/keys/mykey/abc123def456
The plugin automatically resolves all these formats.
Key Versioning
Azure Key Vault uses key versions. When you create a key, a version is automatically created. The plugin:
- Uses the latest version by default when only key name is provided
- Supports explicit version specification
- Returns the full key URL (including version) as the key ID
Error Handling
The plugin maps Azure Key Vault exceptions to TrustWeave exceptions:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
val key = kms.generateKey(Algorithm.P256)
} catch (e: UnsupportedAlgorithmException) {
println("Algorithm not supported: ${e.message}")
} catch (e: KeyNotFoundException) {
println("Key not found: ${e.message}")
} catch (e: TrustWeaveException) {
when {
e.message?.contains("Access denied") == true -> {
println("Check Azure RBAC permissions")
}
e.message?.contains("Key not found") == true -> {
println("Key does not exist")
}
else -> {
println("Error: ${e.message}")
}
}
}
Common Errors
| Error | Cause | Solution |
|---|---|---|
HttpResponseException (403) |
Insufficient RBAC permissions | Grant Key Vault Crypto Officer or Key Vault Crypto User role |
ResourceNotFoundException (404) |
Key doesn’t exist | Verify key name/URL is correct |
UnsupportedAlgorithmException |
Algorithm not supported | Check algorithm compatibility table |
IllegalArgumentException |
Missing required config | Ensure vaultUrl is provided |
Azure RBAC Permissions
Your Azure identity (Managed Identity or Service Principal) needs the following permissions:
Minimum Required Permissions
1
2
3
4
5
# Grant Key Vault Crypto User role (read and sign)
az role assignment create \
--role "Key Vault Crypto User" \
--assignee <managed-identity-object-id> \
--scope /subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.KeyVault/vaults/{vault-name}
Recommended Roles
For full key management capabilities:
- Key Vault Crypto Officer - Full key management access (create, delete, manage)
- Key Vault Crypto User - Sign and verify operations
- Key Vault Secrets User - If using secrets (not applicable for keys)
Access Policy (Classic)
If using access policies instead of RBAC:
1
2
3
az keyvault set-policy --name myvault \
--object-id <managed-identity-object-id> \
--key-permissions get list create sign verify delete recover backup restore
Algorithm Compatibility
See the Algorithm Compatibility Table for detailed comparison of algorithm support across DIDs, VCs, AWS KMS, Azure Key Vault, and Google Cloud KMS.
Key Points:
- ✅ secp256k1 supported for blockchain integration
- ✅ All NIST curves (P-256/P-384/P-521) supported
- ✅ RSA keys supported for legacy compatibility
- ❌ Ed25519 not supported (use P-256, P-384, or P-521 as alternatives)
- ❌ BLS12-381 not supported (requires specialized KMS)
Best Practices
- Use Managed Identity: Prefer Managed Identity over Service Principal for production
- Key Naming: Use descriptive key names with versioning strategy
- Key Tags: Use tags to organize keys by environment, purpose, etc.
- Soft Delete: Enable soft delete on Key Vault for key recovery
- Error Handling: Implement proper error handling for Azure exceptions
- Key Lifecycle: Plan key rotation and deletion schedules
- Access Control: Use Azure RBAC to restrict key access
- Key Versioning: Understand that Azure Key Vault uses key versions internally
- Network Security: Use private endpoints for Key Vault access in production
- Monitoring: Enable Azure Monitor and Key Vault logging
Testing
Unit Tests
The module includes unit tests that can be run without Azure credentials:
1
./gradlew :kms/plugins/azure:test
Integration Tests
For integration testing, use a test Azure Key Vault:
1
2
3
4
5
6
7
// Configure for test Key Vault
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://testvault.vault.azure.net",
"clientId" to "test-client-id",
"clientSecret" to "test-client-secret",
"tenantId" to "test-tenant-id"
))
Local Testing with Azure Key Vault Emulator
For local development, you can use the Azure Key Vault emulator (if available):
1
2
3
4
val kms = azureProvider?.create(mapOf(
"vaultUrl" to "https://localhost:8443",
"endpointOverride" to "https://localhost:8443"
))
Using with TrustWeave
Basic Setup
1
2
3
4
5
6
7
8
9
10
import com.trustweave.*
import com.trustweave.azurekms.*
val TrustWeave = TrustWeave.create {
kms = AzureKeyManagementService(
AzureKmsConfig.builder()
.vaultUrl("https://myvault.vault.azure.net")
.build()
)
}
With SPI Auto-Discovery
1
2
3
4
val TrustWeave = TrustWeave.create {
// Azure Key Vault will be discovered automatically if on classpath
// Configure via environment variables or system properties
}
With Managed Identity
1
2
3
4
5
6
7
8
9
// When running on Azure infrastructure, Managed Identity is used automatically
val TrustWeave = TrustWeave.create {
kms = AzureKeyManagementService(
AzureKmsConfig.builder()
.vaultUrl("https://myvault.vault.azure.net")
// No credentials needed - uses Managed Identity
.build()
)
}
Key Rotation Strategies
Azure Key Vault supports key versioning, which can be used for rotation:
1. Manual Rotation with New Versions
Create a new key version when rotating:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Step 1: Create new key version (Azure Key Vault doesn't support this directly via API)
// Instead, create a new key with a new name
val newKey = kms.generateKey(
algorithm = Algorithm.P256,
options = mapOf(
"keyName" to "issuer-key-v2",
"tags" to mapOf(
"version" to "2",
"rotated" to "2025-01-15"
)
)
)
// Step 2: Update DID document (see key-rotation.md)
// Step 3: Switch issuance to new key
// Step 4: Maintain old key for historical verification
// Step 5: Eventually delete old key after credentials expire
2. Using Key Names for Rotation
Use different key names for each rotation:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create initial key
val key1 = kms.generateKey(
algorithm = Algorithm.P256,
options = mapOf("keyName" to "issuer-key-v1")
)
// Later, create rotated key
val key2 = kms.generateKey(
algorithm = Algorithm.P256,
options = mapOf("keyName" to "issuer-key-v2")
)
// Update your application to use key2
// Keep key1 for historical verification
Security Considerations
- Network Security: Use private endpoints for Key Vault access in production
- Access Control: Implement least-privilege access using Azure RBAC
- Key Vault Firewall: Configure firewall rules to restrict access
- Soft Delete: Enable soft delete for key recovery capabilities
- Monitoring: Enable Azure Monitor and Key Vault logging
- Key Backup: Consider backing up keys before deletion
- Compliance: Azure Key Vault meets various compliance standards (SOC 2, ISO 27001, etc.)
Related Documentation
- Key Management Guide - Core KMS concepts
- Algorithm Compatibility Table - Algorithm support comparison
- Key Rotation Guide - Key rotation strategies
- Creating Plugins Guide - Custom KMS implementations