DEV Community

Thesius Code
Thesius Code

Posted on • Originally published at datanest-stores.pages.dev

Secrets Management Guide

Secrets Management Guide

A zero-trust secrets architecture guide with production-ready HashiCorp Vault configurations and cloud-native secrets manager integrations. Covers the full lifecycle — generation, storage, access, rotation, and revocation — with working HCL configs, Python scripts, and patterns that eliminate hardcoded credentials.

Key Features

  • HashiCorp Vault Setup — Complete HCL configurations for Vault server, including Raft storage, auto-unseal with cloud KMS, and HA clustering.
  • Dynamic Secrets Engine — Generate short-lived database credentials, cloud IAM keys, and PKI certificates on demand.
  • Rotation Automation — Python scripts for rotating passwords, API keys, and TLS certificates on schedule.
  • Access Policy Templates — Vault ACL policies implementing least-privilege for devs, CI/CD, and apps.
  • Cloud Secrets Integration — Wrapper scripts for AWS Secrets Manager, Azure Key Vault, and GCP Secret Manager.
  • Emergency Revocation — Runbooks for immediate credential revocation and key rotation.
  • Secret Detection Scanner — Python script scanning codebases for committed secrets.

Quick Start

# Extract the guide
unzip secrets-management-guide.zip
cd secrets-management-guide/

# Scan your codebase for hardcoded secrets
python3 scripts/secret_scanner.py --path /path/to/your/project --output findings.json

# Deploy Vault with the provided config
cp configs/vault/vault.hcl /etc/vault.d/vault.hcl
vault server -config=/etc/vault.d/vault.hcl

# Initialize and unseal
vault operator init -key-shares=5 -key-threshold=3
vault operator unseal  # Repeat with 3 different keys
Enter fullscreen mode Exit fullscreen mode

Vault Server Configuration

# configs/vault/vault.hcl — Production Vault configuration
storage "raft" {
  path    = "/opt/vault/data"
  node_id = "vault-node-1"
}

listener "tcp" {
  address       = "0.0.0.0:8200"
  tls_cert_file = "/opt/vault/tls/vault-cert.pem"
  tls_key_file  = "/opt/vault/tls/vault-key.pem"
  tls_disable   = false
}

# Auto-unseal with cloud KMS (eliminates manual unseal keys)
seal "awskms" {
  region     = "us-east-1"
  kms_key_id = "YOUR_KMS_KEY_ID_HERE"
}

api_addr     = "https://vault.example.com:8200"
cluster_addr = "https://vault-node-1.example.com:8201"
ui           = true
Enter fullscreen mode Exit fullscreen mode

Architecture / How It Works

Application ──► Auth Method ──► Vault Server ──► Secrets Engine
                (AppRole,           │            (KV, DB, PKI, AWS)
                 K8s SA)            │
                                    ▼
Application ◄── Short-lived    Rotation Scheduler
                Credential     (auto-rotate on schedule)
                (auto-renew)
Enter fullscreen mode Exit fullscreen mode

Every secret has a lease. Applications fetch credentials at runtime and renew before expiry. No secret is permanent.

Usage Examples

Secret Scanner

import re
from pathlib import Path

class SecretScanner:
    """Detect hardcoded secrets in source code."""

    PATTERNS: dict[str, str] = {
        "aws_access_key": r"AKIA[0-9A-Z]{16}",
        "private_key": r"-----BEGIN (?:RSA |EC )?PRIVATE KEY-----",
        "generic_api_key": r"(?i)(?:api[_-]?key|apikey)\s*[=:]\s*['\"][A-Za-z0-9]{20,}",
        "generic_secret": r"(?i)(?:secret|password|passwd)\s*[=:]\s*['\"][^'\"]{8,}",
    }

    def __init__(self, project_path: str):
        self.project_path = Path(project_path)

    def scan(self) -> list[dict]:
        findings = []
        ignore = {".pyc", ".png", ".jpg", ".gif", ".ico"}
        for fp in self.project_path.rglob("*"):
            if not fp.is_file() or fp.suffix in ignore:
                continue
            try:
                text = fp.read_text(encoding="utf-8", errors="ignore")
            except OSError:
                continue
            for num, line in enumerate(text.splitlines(), 1):
                for stype, pat in self.PATTERNS.items():
                    if re.search(pat, line):
                        findings.append({"file": str(fp.relative_to(self.project_path)),
                                         "line": num, "type": stype, "severity": "CRITICAL"})
        return findings
Enter fullscreen mode Exit fullscreen mode

Vault ACL Policy — Application Role

# policies/app-readonly.hcl — Least-privilege for applications
path "secret/data/apps/{{identity.entity.aliases.auth_approle_12345.metadata.app_name}}/*" {
  capabilities = ["read"]
}
path "auth/token/renew-self" { capabilities = ["update"] }
path "sys/leases/renew"      { capabilities = ["update"] }
path "secret/data/apps/*"    { capabilities = ["deny"]   }
path "sys/*"                 { capabilities = ["deny"]   }
Enter fullscreen mode Exit fullscreen mode

Password Rotation

import secrets
import string

def generate_secure_password(length: int = 32) -> str:
    """Generate a cryptographically secure password meeting complexity requirements."""
    alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
    while True:
        pw = "".join(secrets.choice(alphabet) for _ in range(length))
        if (any(c.islower() for c in pw) and any(c.isupper() for c in pw)
                and any(c.isdigit() for c in pw) and any(c in "!@#$%^&*" for c in pw)):
            return pw
Enter fullscreen mode Exit fullscreen mode

Configuration

Parameter Default Description
vault.address https://vault.example.com:8200 Vault server URL
vault.auth_method approle Auth method for apps
vault.token_ttl 1h Token time-to-live
rotation.schedule 30d Default rotation interval
rotation.password_length 32 Generated password length
scanner.exclude_dirs [".git", "venv"] Dirs to skip

Best Practices

  1. Never store secrets in code — Use environment variables locally, Vault/Secrets Manager for everything else.
  2. Use dynamic secrets — Short-lived credentials on demand beat static passwords.
  3. Rotate on schedule AND on suspicion — 30-day automated rotation is baseline; rotate immediately on compromise.
  4. Audit all access — Every secret read/write should produce an immutable audit entry.
  5. Separate environments strictly — Dev, staging, and prod must use separate secret paths and credentials.

Troubleshooting

Problem Cause Fix
Vault sealed after restart Auto-unseal not configured or KMS key inaccessible Verify KMS key permissions; check seal stanza in vault.hcl
Application gets 403 from Vault Policy too restrictive or wrong auth role Check vault policy read <policy> and verify AppRole bindings
Secret scanner false positives Pattern matches example code or test fixtures Add file paths to scanner.ignore_paths in config
Rotation script fails silently Database connection rejected during password change Use dual-password rotation: set new password before revoking old

This is 1 of 9 resources in the Security Engineer Pro toolkit. Get the complete [Secrets Management Guide] with all files, templates, and documentation for $29.

Get the Full Kit →

Or grab the entire Security Engineer Pro bundle (9 products) for $119 — save 30%.

Get the Complete Bundle →


Related Articles

Top comments (0)