Skip to content
StackPractices
intermediate By StackPractices

Secrets Management: Vault, Cloud Managers

A practical guide to secrets management: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, and GCP Secret Manager with rotation, access control, and CI/CD integration.

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

Secrets — passwords, API keys, tokens, certificates — are the keys to your kingdom. Storing them in source code, configuration files, or environment variables is a common source of breaches. Proper secrets management ensures credentials are encrypted, rotated, audited, and accessible only to authorized services and users. The following walks through the leading secret management solutions and the practices that make them useful.

When to Use

  • For alternatives, see Complete Guide to Secrets Management.

  • You have credentials, API keys, or certificates to protect

  • You need to share secrets across teams or services

  • You want to audit who accessed what secret and when

  • You are building a CI/CD pipeline that needs runtime secrets

What Not to Do

Anti-PatternWhy It FailsWhat to Do Instead
Hardcode secrets in sourceCommits to Git are forever; history leaksUse secret references
Store secrets in env varsVisible in process dumps, /proc, and debug endpointsUse secret managers with runtime injection
Share one password across servicesBlast radius is entire infrastructureService-specific credentials
Never rotate secretsCompromised keys remain valid indefinitelyAutomate rotation
Send secrets in Slack/emailUnencrypted, unlogged, uncontrolledUse approved secret sharing tools

HashiCorp Vault

The open-source standard for secrets management.

Core Concepts

ComponentPurpose
Secrets EngineStores or generates secrets (KV, database, PKI, AWS)
Auth MethodHow users/services authenticate (Kubernetes, OIDC, AppRole)
PolicyFine-grained access control (ACL)
On-demand SecretShort-lived, automatically revoked credentials

On-demand Database Credentials

# Enable database secrets engine
vault secrets enable database

# Configure PostgreSQL connection
vault write database/config/my-postgresql \
  plugin_name=postgresql-database-plugin \
  allowed_roles="app" \
  connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb" \
  username="vaultadmin" \
  password="vaultpass"

# Create a role that generates 1-hour leases
vault write database/roles/app \
  db_name=my-postgresql \
  creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';" \
  default_ttl="1h" \
  max_ttl="24h"

Reading Secrets in Applications

import hvac

client = hvac.Client(url='https://vault.example.com')
client.auth.kubernetes.login(role='my-app', jwt=service_account_token)

# Read a static secret
secret = client.secrets.kv.v2.read_secret_version(path='my-app/config')
api_key = secret['data']['data']['api_key']

# Generate on-demand database credentials
db_creds = client.secrets.database.generate_credentials(name='app')
username = db_creds['data']['username']
password = db_creds['data']['password']

AWS Secrets Manager

Fully managed secret rotation for AWS workloads.

# Create a secret
aws secretsmanager create-secret \
  --name prod/database/password \
  --secret-string '{"username":"admin","password":"supersecret"}'

# Retrieve a secret
aws secretsmanager get-secret-value --secret-id prod/database/password

# Configure automatic rotation
aws secretsmanager rotate-secret \
  --secret-id prod/database/password \
  --rotation-lambda-arn arn:aws:lambda:...:function:rotation \
  --automatically-after-days 30

IAM Policy for Access

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["secretsmanager:GetSecretValue"],
      "Resource": "arn:aws:secretsmanager:*:*:secret:prod/*",
      "Condition": {
        "StringEquals": {
          "aws:SourceVpc": "vpc-12345"
        }
      }
    }
  ]
}

Azure Key Vault

Integrated with Azure AD and Microsoft ecosystems.

# Create a Key Vault
az keyvault create --name myvault --resource-group mygroup --location eastus

# Store a secret
az keyvault secret set --vault-name myvault --name db-password --value secret123

# Retrieve a secret
az keyvault secret show --vault-name myvault --name db-password

Managed Identity Access

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

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

secret = client.get_secret("db-password")
print(secret.value)

GCP Secret Manager

Native integration with GCP IAM and Cloud Run.

# Create a secret
echo -n "supersecret" | gcloud secrets create db-password --data-file=-

# Add a version
echo -n "newsecret" | gcloud secrets versions add db-password --data-file=-

# Access from Cloud Run (no code changes needed)
gcloud run deploy my-app --set-secrets=DB_PASSWORD=db-password:latest

CI/CD Integration

GitHub Actions with OIDC

jobs:
  deploy:
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: us-east-1
      - run: |
          DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id db-password --query SecretString --output text)
          echo "DB_PASSWORD=$DB_PASSWORD" >> $GITHUB_ENV

Secrets Scanning in Pipelines

# Detect secrets before merge
 trufflehog filesystem --directory=.
 gitleaks detect --source .
 detect-secrets scan

Rotation Strategies

StrategyBest ForComplexity
ManualAd-hoc, small teamsLow
Lambda/FunctionAWS RDS, standard databasesMedium
Vault On-demandMicroservices, multi-cloudHigh
Certificate AutoTLS certificates (Let’s Encrypt, ACM)Low

Common Mistakes

  • Using one secret for all environments — separate prod, staging, and dev secrets
  • No audit logging — you cannot investigate breaches without access logs
  • Overly permissive policies — a compromised CI/CD token should not access production secrets
  • Ignoring secret sprawl — old API keys in environment variables, logs, and backups
  • No revocation plan — when a secret leaks, how quickly can you rotate it?

FAQ

Should I use Vault or a cloud-native manager? Use Vault for multi-cloud, complex workflows, or on-demand secrets. Use cloud-native managers (AWS, Azure, GCP) for simplicity and tight integration with that cloud.

How often should I rotate secrets?

  • Database credentials: 30-90 days
  • API keys: 90 days or on employee departure
  • TLS certificates: before expiry (typically annually)
  • Emergency: immediately on suspected compromise

Can I prevent developers from seeing secrets? Yes. Grant read but not list or update. Use live credentials so developers get temporary, limited permissions without seeing the root password.

How do I get started with this in an existing project?

Start with a small, isolated part of your codebase. Apply the concepts from this guide to one module or service. Measure the impact, then expand to other areas.

What tools do I need?

The tools mentioned throughout this guide are listed in each section. Most are open-source and widely adopted. Check the related resources for setup instructions.

How do I measure success after implementing this?

Define clear metrics before starting: performance benchmarks, error rates, or maintainability indicators. Compare before and after. Iterate based on the data, not on assumptions.

Advanced Topics

Scenario: Secrets Management for Microservices

System: 10 microservices on K8s, AWS
Stack: AWS Secrets Manager + External Secrets Operator

Architecture:
  Developer -> GitHub (secret in repo: NEVER)
  Developer -> AWS Secrets Manager (manual or CLI)
  Secrets Manager -> External Secrets Operator (K8s)
  ESO -> creates Kubernetes Secret
  Pod -> mounts Secret as env var or volume

Secret rules:
  | Rule | Reason |
  |------|--------|
  | Never in code | Git history is permanent |
  | Never in .env in prod | Plaintext file on disk |
  | Never in logs | Logs are accessible |
  | Never in error messages | Exposes to client |
  | Automatic rotation | Minimizes leak impact |
  | Least privilege | Each service only accesses its secrets |
  | Audit log | Who accessed which secret and when |

```yaml
# External Secrets Operator - ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: payment-service-secrets
  namespace: production
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secretsmanager
    kind: ClusterSecretStore
  target:
    name: payment-service-secrets
    creationPolicy: Owner
  data:
    - secretKey: DATABASE_URL
      remoteRef:
        key: production/payment-service/database-url
    - secretKey: STRIPE_SECRET_KEY
      remoteRef:
        key: production/payment-service/stripe-key
    - secretKey: JWT_PRIVATE_KEY
      remoteRef:
        key: production/payment-service/jwt-private

Automatic rotation (Secrets Manager):

  • Database: rotate every 30 days (Lambda function)
  • Stripe: manual rotation (API does not support auto-rotation)
  • JWT: rotate every 90 days (deploy new key, keep old 7 days)
  • API keys: rotate every 60 days

Leak detection:

  • git-secrets: pre-commit hook blocks commits with patterns
  • TruffleHog: scans git history
  • GitHub Secret Scanning: automatic alerts
  • AWS CloudTrail: audit log of Secrets Manager access

Lessons:

  • External Secrets Operator syncs secrets without manual K8s secrets
  • Automatic rotation minimizes leak impact
  • git-secrets in pre-commit is the first line of defense
  • Each service should have its own secrets (no sharing)
  • Audit log of secret access is mandatory for SOC2

### How do I rotate secrets without downtime?

Use the dual-secret pattern: configure the new secret while the old one is still active. Deploy the app with the new secret. Verify it works. After confirming, invalidate the old one. For JWT, accept both keys during a transition period (7 days). For DB, rotate the password via Secrets Manager with a Lambda that updates the password and refreshes the pods.
Guide

Secure Coding Practices — By Language and Pattern

A practical guide to secure coding practices across languages: input validation, memory safety, authentication, and defensive patterns for Python, Java, JavaScript, and Go.

Guide

Cryptography Basics — Encryption, Hashing, and Signing

A developer's guide to cryptography: symmetric and asymmetric encryption, hashing, digital signatures, and key management with practical code examples.

Guide

Zero Trust Architecture — Never Trust, Always Verify

A practical guide to implementing Zero Trust architecture: identity verification, least privilege, micro-segmentation, and continuous validation for modern systems.

Guide

CI/CD Security: Harden Your Pipelines and Prevent Supply

A practical guide to securing CI/CD pipelines: secrets management, least-privilege runners, artifact signing, dependency scanning, and defending against supply chain attacks.

Recipe

Encrypt and Decrypt Data with AES-GCM in Python

Encrypt sensitive data using AES-GCM with the cryptography library. Covers key derivation, nonce generation, authenticated encryption, and file encryption.

Guide

Blob Storage: S3, GCS, and Azure Blob Patterns for Engineers

A practical guide to cloud blob storage: bucket design, access control, lifecycle policies, multipart uploads, presigned URLs, and cost optimization patterns for S3, Google Cloud Storage, and Azure Blob.

Guide

Complete Guide to Web Security Headers

Implement CSP, HSTS, X-Frame-Options, and secure headers. Covers content security policy, CORS, referrer policy, permissions policy, and testing with security scanners.