KMS Simplification Migration Guide
Version: 0.2.0 Date: 2025-10-08 Status: Active
Overview
The KMS service has been simplified from supporting 4 backends (Vault, AWS KMS, Age, Cosmian) to supporting only 2 backends:
- Age: Development and local testing
- Cosmian KMS: Production deployments
This simplification reduces complexity, removes unnecessary cloud provider dependencies, and provides a clearer separation between development and production use cases.
What Changed
Removed
- ❌ HashiCorp Vault backend (
src/vault/) - ❌ AWS KMS backend (
src/aws/) - ❌ AWS SDK dependencies (
aws-sdk-kms,aws-config,aws-credential-types) - ❌ Envelope encryption helpers (AWS-specific)
- ❌ Complex multi-backend configuration
Added
- ✅ Age backend for development (
src/age/) - ✅ Cosmian KMS backend for production (
src/cosmian/) - ✅ Simplified configuration (
provisioning/config/kms.toml) - ✅ Clear dev/prod separation
- ✅ Better error messages
Modified
- 🔄
KmsBackendConfigenum (now only Age and Cosmian) - 🔄
KmsErrorenum (removed Vault/AWS-specific errors) - 🔄 Service initialization logic
- 🔄 README and documentation
- 🔄 Cargo.toml dependencies
Why This Change?
Problems with Previous Approach
- Unnecessary Complexity: 4 backends for simple use cases
- Cloud Lock-in: AWS KMS dependency limited flexibility
- Operational Overhead: Vault requires server setup even for dev
- Dependency Bloat: AWS SDK adds significant compile time
- Unclear Use Cases: When to use which backend?
Benefits of Simplified Approach
- Clear Separation: Age = dev, Cosmian = prod
- Faster Compilation: Removed AWS SDK (saves ~30s)
- Offline Development: Age works without network
- Enterprise Security: Cosmian provides confidential computing
- Easier Maintenance: 2 backends instead of 4
Migration Steps
For Development Environments
If you were using Vault or AWS KMS for development:
Step 1: Install Age
# macOS
brew install age
# Ubuntu/Debian
apt install age
# From source
go install filippo.io/age/cmd/...@latest
Step 2: Generate Age Keys
mkdir -p ~/.config/provisioning/age
age-keygen -o ~/.config/provisioning/age/private_key.txt
age-keygen -y ~/.config/provisioning/age/private_key.txt > ~/.config/provisioning/age/public_key.txt
Step 3: Update Configuration
Replace your old Vault/AWS config:
Old (Vault):
[kms]
type = "vault"
address = "http://localhost:8200"
token = "${VAULT_TOKEN}"
mount_point = "transit"
New (Age):
[kms]
environment = "dev"
[kms.age]
public_key_path = "~/.config/provisioning/age/public_key.txt"
private_key_path = "~/.config/provisioning/age/private_key.txt"
Step 4: Re-encrypt Development Secrets
# Export old secrets (if using Vault)
vault kv get -format=json secret/dev > dev-secrets.json
# Encrypt with Age
cat dev-secrets.json | age -r $(cat ~/.config/provisioning/age/public_key.txt) > dev-secrets.age
# Test decryption
age -d -i ~/.config/provisioning/age/private_key.txt dev-secrets.age
For Production Environments
If you were using Vault or AWS KMS for production:
Step 1: Set Up Cosmian KMS
Choose one of these options:
Option A: Cosmian Cloud (Managed)
# Sign up at https://cosmian.com
# Get API credentials
export COSMIAN_KMS_URL=https://kms.cosmian.cloud
export COSMIAN_API_KEY=your-api-key
Option B: Self-Hosted Cosmian KMS
# Deploy Cosmian KMS server
# See: https://docs.cosmian.com/kms/deployment/
# Configure endpoint
export COSMIAN_KMS_URL=https://kms.example.com
export COSMIAN_API_KEY=your-api-key
Step 2: Create Master Key in Cosmian
# Using Cosmian CLI
cosmian-kms create-key \
--algorithm AES \
--key-length 256 \
--key-id provisioning-master-key
# Or via API
curl -X POST $COSMIAN_KMS_URL/api/v1/keys \
-H "X-API-Key: $COSMIAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"algorithm": "AES",
"keyLength": 256,
"keyId": "provisioning-master-key"
}'
Step 3: Migrate Production Secrets
From Vault to Cosmian:
# Export secrets from Vault
vault kv get -format=json secret/prod > prod-secrets.json
# Import to Cosmian
# (Use temporary Age encryption for transfer)
cat prod-secrets.json | \
age -r $(cat ~/.config/provisioning/age/public_key.txt) | \
base64 > prod-secrets.enc
# On production server with Cosmian
cat prod-secrets.enc | \
base64 -d | \
age -d -i ~/.config/provisioning/age/private_key.txt | \
# Re-encrypt with Cosmian
curl -X POST $COSMIAN_KMS_URL/api/v1/encrypt \
-H "X-API-Key: $COSMIAN_API_KEY" \
-d @-
From AWS KMS to Cosmian:
# Decrypt with AWS KMS
aws kms decrypt \
--ciphertext-blob fileb://encrypted-data \
--output text \
--query Plaintext | \
base64 -d > plaintext-data
# Encrypt with Cosmian
curl -X POST $COSMIAN_KMS_URL/api/v1/encrypt \
-H "X-API-Key: $COSMIAN_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"keyId\":\"provisioning-master-key\",\"data\":\"$(base64 plaintext-data)\"}"
Step 4: Update Production Configuration
Old (AWS KMS):
[kms]
type = "aws-kms"
region = "us-east-1"
key_id = "arn:aws:kms:us-east-1:123456789012:key/..."
New (Cosmian):
[kms]
environment = "prod"
[kms.cosmian]
server_url = "${COSMIAN_KMS_URL}"
api_key = "${COSMIAN_API_KEY}"
default_key_id = "provisioning-master-key"
tls_verify = true
use_confidential_computing = false # Enable if using SGX/SEV
Step 5: Test Production Setup
# Set environment
export PROVISIONING_ENV=prod
export COSMIAN_KMS_URL=https://kms.example.com
export COSMIAN_API_KEY=your-api-key
# Start KMS service
cargo run --bin kms-service
# Test encryption
curl -X POST http://localhost:8082/api/v1/kms/encrypt \
-H "Content-Type: application/json" \
-d '{"plaintext":"SGVsbG8=","context":"env=prod"}'
# Test decryption
curl -X POST http://localhost:8082/api/v1/kms/decrypt \
-H "Content-Type: application/json" \
-d '{"ciphertext":"...","context":"env=prod"}'
Configuration Comparison
Before (4 Backends)
# Development could use any backend
[kms]
type = "vault" # or "aws-kms"
address = "http://localhost:8200"
token = "${VAULT_TOKEN}"
# Production used Vault or AWS
[kms]
type = "aws-kms"
region = "us-east-1"
key_id = "arn:aws:kms:..."
After (2 Backends)
# Clear environment-based selection
[kms]
dev_backend = "age"
prod_backend = "cosmian"
environment = "${PROVISIONING_ENV:-dev}"
# Age for development
[kms.age]
public_key_path = "~/.config/provisioning/age/public_key.txt"
private_key_path = "~/.config/provisioning/age/private_key.txt"
# Cosmian for production
[kms.cosmian]
server_url = "${COSMIAN_KMS_URL}"
api_key = "${COSMIAN_API_KEY}"
default_key_id = "provisioning-master-key"
tls_verify = true
Breaking Changes
API Changes
Removed Functions
generate_data_key()- Now only available with Cosmian backendenvelope_encrypt()- AWS-specific, removedenvelope_decrypt()- AWS-specific, removedrotate_key()- Now handled server-side by Cosmian
Changed Error Types
Before:
KmsError::VaultError(String)
KmsError::AwsKmsError(String)
After:
KmsError::AgeError(String)
KmsError::CosmianError(String)
Updated Configuration Enum
Before:
enum KmsBackendConfig {
Vault { address, token, mount_point, ... },
AwsKms { region, key_id, assume_role },
}
After:
enum KmsBackendConfig {
Age { public_key_path, private_key_path },
Cosmian { server_url, api_key, default_key_id, tls_verify },
}
Code Migration
Rust Code
Before (AWS KMS):
use kms_service::{KmsService, KmsBackendConfig};
let config = KmsBackendConfig::AwsKms {
region: "us-east-1".to_string(),
key_id: "arn:aws:kms:...".to_string(),
assume_role: None,
};
let kms = KmsService::new(config).await?;
After (Cosmian):
use kms_service::{KmsService, KmsBackendConfig};
let config = KmsBackendConfig::Cosmian {
server_url: env::var("COSMIAN_KMS_URL")?,
api_key: env::var("COSMIAN_API_KEY")?,
default_key_id: "provisioning-master-key".to_string(),
tls_verify: true,
};
let kms = KmsService::new(config).await?;
Nushell Code
Before (Vault):
# Set Vault environment
$env.VAULT_ADDR = "http://localhost:8200"
$env.VAULT_TOKEN = "root"
# Use KMS
kms encrypt "secret-data"
After (Age for dev):
# Set environment
$env.PROVISIONING_ENV = "dev"
# Age keys automatically loaded from config
kms encrypt "secret-data"
Rollback Plan
If you need to rollback to Vault/AWS KMS:
# Checkout previous version
git checkout tags/v0.1.0
# Rebuild with old dependencies
cd provisioning/platform/kms-service
cargo clean
cargo build --release
# Restore old configuration
cp provisioning/config/kms.toml.backup provisioning/config/kms.toml
Testing the Migration
Development Testing
# 1. Generate Age keys
age-keygen -o /tmp/test_private.txt
age-keygen -y /tmp/test_private.txt > /tmp/test_public.txt
# 2. Test encryption
echo "test-data" | age -r $(cat /tmp/test_public.txt) > /tmp/encrypted
# 3. Test decryption
age -d -i /tmp/test_private.txt /tmp/encrypted
# 4. Start KMS service with test keys
export PROVISIONING_ENV=dev
# Update config to point to /tmp keys
cargo run --bin kms-service
Production Testing
# 1. Set up test Cosmian instance
export COSMIAN_KMS_URL=https://kms-staging.example.com
export COSMIAN_API_KEY=test-api-key
# 2. Create test key
cosmian-kms create-key --key-id test-key --algorithm AES --key-length 256
# 3. Test encryption
curl -X POST $COSMIAN_KMS_URL/api/v1/encrypt \
-H "X-API-Key: $COSMIAN_API_KEY" \
-d '{"keyId":"test-key","data":"dGVzdA=="}'
# 4. Start KMS service
export PROVISIONING_ENV=prod
cargo run --bin kms-service
Troubleshooting
Age Keys Not Found
# Check keys exist
ls -la ~/.config/provisioning/age/
# Regenerate if missing
age-keygen -o ~/.config/provisioning/age/private_key.txt
age-keygen -y ~/.config/provisioning/age/private_key.txt > ~/.config/provisioning/age/public_key.txt
Cosmian Connection Failed
# Check network connectivity
curl -v $COSMIAN_KMS_URL/api/v1/health
# Verify API key
curl $COSMIAN_KMS_URL/api/v1/version \
-H "X-API-Key: $COSMIAN_API_KEY"
# Check TLS certificate
openssl s_client -connect kms.example.com:443
Compilation Errors
# Clean and rebuild
cd provisioning/platform/kms-service
cargo clean
cargo update
cargo build --release
Support
- Documentation: See README.md
- Issues: Report on project issue tracker
- Cosmian Support: https://docs.cosmian.com/support/
Timeline
- 2025-10-08: Migration guide published
- 2025-10-15: Deprecation notices for Vault/AWS
- 2025-11-01: Old backends removed from codebase
- 2025-11-15: Migration complete, old configs unsupported
FAQs
Q: Can I still use Vault if I really need to? A: No, Vault support has been removed. Use Age for dev or Cosmian for prod.
Q: What about AWS KMS for existing deployments? A: Migrate to Cosmian KMS. The API is similar, and migration tools are provided.
Q: Is Age secure enough for production? A: No. Age is designed for development only. Use Cosmian KMS for production.
Q: Does Cosmian support confidential computing? A: Yes, Cosmian KMS supports SGX and SEV for confidential computing workloads.
Q: How much does Cosmian cost? A: Cosmian offers both cloud and self-hosted options. Contact Cosmian for pricing.
Q: Can I use my own KMS backend? A: Not currently supported. Only Age and Cosmian are available.
Checklist
Use this checklist to track your migration:
Development Migration
-
Install Age (
brew install ageor equivalent) -
Generate Age keys (
age-keygen) -
Update
provisioning/config/kms.tomlto use Age backend - Export secrets from Vault/AWS (if applicable)
- Re-encrypt secrets with Age
- Test KMS service startup
- Test encrypt/decrypt operations
- Update CI/CD pipelines (if applicable)
- Update documentation
Production Migration
- Set up Cosmian KMS server (cloud or self-hosted)
- Create master key in Cosmian
- Export production secrets from Vault/AWS
- Re-encrypt secrets with Cosmian
-
Update
provisioning/config/kms.tomlto use Cosmian backend -
Set environment variables (
COSMIAN_KMS_URL,COSMIAN_API_KEY) - Test KMS service startup in staging
- Test encrypt/decrypt operations in staging
- Load test Cosmian integration
- Update production deployment configs
- Deploy to production
- Verify all secrets accessible
- Decommission old KMS infrastructure
Conclusion
The KMS simplification reduces complexity while providing better separation between development and production use cases. Age offers a fast, offline solution for development, while Cosmian KMS provides enterprise-grade security for production deployments.
For questions or issues, please refer to the documentation or open an issue.