Verified by Garnet Grid

Secrets Management: Vault, AWS SM, Azure KV Compared

Compare secrets management solutions for enterprise applications. Covers HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and implementation patterns for application secrets, API keys, and certificates.

Hardcoded secrets in source code remain the #1 cause of credential leaks. According to GitGuardian’s State of Secrets Sprawl report, over 10 million secrets are leaked in public Git repositories every year. Secrets management solutions centralize storage, automate rotation, provide audit trails, and enforce access policies. This guide compares the top three solutions and shows battle-tested implementation patterns, rotation strategies, and the anti-patterns that cause breaches.


What Counts as a Secret

Before comparing tools, be clear about what needs protection:

  • Database credentials — Connection strings, usernames, passwords for PostgreSQL, MySQL, SQL Server, MongoDB
  • API keys — Stripe, Twilio, SendGrid, AWS access keys, Azure service principal credentials
  • TLS certificates — SSL/TLS certs for HTTPS, mTLS between services, client certificates
  • Encryption keys — Keys used for data encryption at rest or in transit
  • OAuth tokens — Client secrets for OAuth2 flows, refresh tokens, JWT signing keys
  • SSH keys — Deployment keys, infrastructure access keys
  • Environment-specific configuration — Connection strings, endpoints, feature flags that vary by environment

If any of these are in your source code, environment variables files checked into Git, or shared via Slack, you have a secrets management problem.


Solution Comparison

FeatureHashiCorp VaultAWS Secrets ManagerAzure Key Vault
HostingSelf-hosted or HCP (cloud)AWS fully managedAzure fully managed
Multi-cloud✅ Best for multi-cloudAWS onlyAzure only
Dynamic secrets✅ Database, cloud creds, PKI❌ Static only❌ Static only
Secret rotationBuilt-in + custom policiesBuilt-in (Lambda-based)Built-in (Azure Functions)
Encryption as a service✅ Transit engine (encrypt without seeing key)❌ Use KMS separately✅ Key management
PKI / certificates✅ Built-in Certificate AuthorityUse ACM (separate service)Certificate management
Authentication methods15+ (AppRole, K8s, LDAP, OIDC, AWS IAM)AWS IAM onlyAzure AD, managed identity
Audit logging✅ Detailed per-request✅ CloudTrail✅ Azure Monitor
HA/DRRaft consensus or ConsulManaged (multi-AZ)Managed (multi-region)
CostOpen source free / HCP from $0.03/secret$0.40/secret/month + $0.05/10K API calls$0.03/10K operations
Best forMulti-cloud, complex enterprise needsAWS-native shopsAzure-native shops

When to Choose Each

HashiCorp Vault: You are multi-cloud, need dynamic secrets (short-lived database credentials generated on demand), or need a built-in PKI. Vault is the most powerful but requires operational expertise — you must manage upgrades, backups, and high availability yourself (unless using HCP Vault).

AWS Secrets Manager: You are fully on AWS and want zero operational overhead. It integrates natively with RDS, Redshift, and DocumentDB for automated rotation. Pay per secret with no infrastructure to manage.

Azure Key Vault: You are fully on Azure and use managed identities. The tightest integration with Azure services (App Service, Functions, AKS). Cheapest per-operation pricing but limited to Azure ecosystem.


Implementation: AWS Secrets Manager

import boto3
import json
from functools import lru_cache

@lru_cache(maxsize=32)
def get_secret(secret_name: str, region: str = "us-east-1") -> dict:
    """Retrieve and cache a secret from AWS Secrets Manager."""
    client = boto3.client('secretsmanager', region_name=region)
    response = client.get_secret_value(SecretId=secret_name)
    return json.loads(response['SecretString'])

# Usage
db_creds = get_secret("prod/database/postgres")
connection = psycopg2.connect(
    host=db_creds['host'],
    user=db_creds['username'],
    password=db_creds['password'],
    dbname=db_creds['dbname']
)

Key considerations:

  • Use lru_cache or a TTL cache to avoid hitting the API on every request (costs add up)
  • Tag secrets with Environment, Service, and Owner for audit and cost allocation
  • Use resource-based policies to limit which IAM roles can access which secrets

Implementation: Azure Key Vault

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
client = SecretClient(vault_url="https://garnet-prod.vault.azure.net/", credential=credential)

db_password = client.get_secret("prod-db-password").value
api_key = client.get_secret("stripe-api-key").value

Key considerations:

  • Use managed identities instead of service principals where possible — no credentials to manage
  • Enable soft delete and purge protection to prevent accidental or malicious deletion
  • Use separate Key Vaults per environment (dev, staging, prod) — never share a vault

Implementation: HashiCorp Vault

import hvac
import os

client = hvac.Client(url='https://vault.internal:8200')
client.auth.approle.login(
    role_id=os.environ['VAULT_ROLE_ID'],
    secret_id=os.environ['VAULT_SECRET_ID']
)

# Read static secret
secret = client.secrets.kv.v2.read_secret_version(path='database/prod')
db_password = secret['data']['data']['password']

# Generate dynamic database credential (short-lived, auto-revoked)
creds = client.secrets.database.generate_credentials(name='readonly')
# Returns: {'username': 'v-approle-readonly-abc123', 'password': 'xyz789', 'ttl': 3600}
# Credential is automatically revoked after TTL expires

Key considerations:

  • Dynamic secrets are Vault’s killer feature — each application instance gets unique, short-lived credentials that are automatically revoked. If compromised, blast radius is one instance for one hour.
  • Use AppRole for machine-to-machine auth, OIDC for human access
  • Set up Vault Agent as a sidecar for automatic token renewal and secret caching

Secret Rotation Patterns

Dual-Secret Rotation (Zero Downtime)

1. Create new secret version (v2) in secrets manager
2. Update credential at source (database password, API key)
3. Application reads new version automatically (or restart)
4. Verify v2 works in production
5. Mark v1 as deprecated (set expiration)
6. Remove v1 after grace period (24-48 hours)

Lambda-Based Rotation (AWS)

AWS Secrets Manager supports automatic rotation via Lambda functions. For RDS databases, AWS provides pre-built Lambda templates:

Rotation interval: 30-90 days
Lambda function: SecretsManagerRDSPostgreSQLRotationSingleUser
Steps: createSecret → setSecret → testSecret → finishSecret

Dynamic Secrets (Vault — Best Pattern)

With dynamic secrets, there is no rotation because credentials are short-lived:

1. Application requests credentials from Vault
2. Vault generates unique username/password on the database
3. Application uses credentials for its session (TTL: 1 hour)
4. Vault automatically revokes credentials when TTL expires
5. No shared credentials, no rotation needed, no credential sprawl

Anti-Patterns

Anti-PatternRisk LevelFix
Secrets in .env files committed to Git🔴 Critical — exposed in repo history foreverAdd .env to .gitignore, use secrets manager, run truffleHog to find existing leaks
Secrets in env vars (shared across processes)🟡 Medium — visible to all processes on hostPer-service secrets with vault injection or sidecar
Same secret in dev and prod🔴 Critical — dev compromise = prod compromiseSeparate secrets per environment, different vaults
Never rotating secrets🟡 Medium — longer exposure window if leakedAuto-rotate every 30-90 days, or use dynamic secrets
Sharing API keys via Slack/email🔴 Critical — logged in chat history, email serversUse vault with short-lived tokens, share vault paths not values
One secret for all microservices🟡 Medium — compromise of one service compromises allPer-service credentials with least privilege
No audit logging on secret access🟡 Medium — cannot detect unauthorized accessEnable audit logging, alert on anomalous access patterns
Long-lived service account keys🟡 Medium — keys that never expire accumulate riskUse managed identities (Azure) or IAM roles (AWS) instead

Rotation Frequency by Secret Type

Secret TypeRotation IntervalAutomationRisk if Not Rotated
Database passwords30 daysLambda / Azure FunctionCredential stuffing, lateral movement
API keys (third-party)90 daysManual or webhookUnauthorized API usage, cost exposure
TLS certificates365 days (auto-renew)ACME / Let’s EncryptService outage, security warnings
OAuth client secrets90 daysApp registration automationToken theft, impersonation
SSH deploy keys180 daysAnsible / TerraformUnauthorized server access
JWT signing keys90 daysRolling key rotationToken forgery
Encryption keys (data at rest)AnnualKMS automaticCompliance violation

Emergency Response: Leaked Secret

When a secret is confirmed leaked, follow this playbook:

  1. Revoke immediately — Disable the compromised credential at its source (database, API provider, cloud console)
  2. Generate replacement — Create a new secret in the vault and update all consumers
  3. Assess blast radius — Determine what the leaked secret had access to and what was accessed
  4. Audit logs — Review access logs for unauthorized activity during the exposure window
  5. Root cause — Identify how the leak occurred (code commit, log exposure, insider) and close the gap
  6. Post-mortem — Document the incident, timeline, and remediation for future reference

Checklist

  • All secrets stored in a dedicated secrets manager (not code, not .env files, not config files)
  • Rotation policy defined and automated (30 days for database passwords, 90 days for API keys, 365 days for certificates)
  • Access policies enforced with least privilege per service (not blanket access)
  • Audit logging enabled on all secret access with alerting for anomalous patterns
  • Secrets scanner running in CI pipeline (truffleHog, git-secrets, Gitleaks)
  • Separate secrets per environment (dev/staging/prod — never shared)
  • Break-glass procedure documented for emergency secret access
  • Secret inventory maintained (what secrets exist, who owns them, when they rotate)
  • Incident response plan includes credential revocation steps
  • Dynamic secrets evaluated for database access (if using Vault)

:::note[Source] This guide is derived from operational intelligence at Garnet Grid Consulting. For security consulting, visit garnetgrid.com. :::

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →