export DATABASE_URL=postgres://admin:supersecret@db:5432/prod
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
docker-compose up
export DATABASE_URL=postgres://admin:supersecret@db:5432/prod
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
docker-compose up
export DATABASE_URL=postgres://admin:supersecret@db:5432/prod
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
docker-compose up
logger.debug(f"Connection config: {dict(os.environ)}")
logger.debug(f"Connection config: {dict(os.environ)}")
logger.debug(f"Connection config: {dict(os.environ)}")
# Vault policy for the API service
path "secret/data/api/*" { capabilities = ["read"]
} path "secret/data/shared/database" { capabilities = ["read"]
} # No access to other services' secrets
path "secret/data/billing/*" { capabilities = ["deny"]
}
# Vault policy for the API service
path "secret/data/api/*" { capabilities = ["read"]
} path "secret/data/shared/database" { capabilities = ["read"]
} # No access to other services' secrets
path "secret/data/billing/*" { capabilities = ["deny"]
}
# Vault policy for the API service
path "secret/data/api/*" { capabilities = ["read"]
} path "secret/data/shared/database" { capabilities = ["read"]
} # No access to other services' secrets
path "secret/data/billing/*" { capabilities = ["deny"]
}
# docker-compose.yml
services: api: image: registry.local/api:latest volumes: - secrets-vol:/run/secrets:ro depends_on: - vault-agent vault-agent: image: hashicorp/vault:latest command: vault agent -config=/etc/vault-agent.hcl volumes: - secrets-vol:/run/secrets volumes: secrets-vol: driver: local driver_opts: type: tmpfs device: tmpfs
# docker-compose.yml
services: api: image: registry.local/api:latest volumes: - secrets-vol:/run/secrets:ro depends_on: - vault-agent vault-agent: image: hashicorp/vault:latest command: vault agent -config=/etc/vault-agent.hcl volumes: - secrets-vol:/run/secrets volumes: secrets-vol: driver: local driver_opts: type: tmpfs device: tmpfs
# docker-compose.yml
services: api: image: registry.local/api:latest volumes: - secrets-vol:/run/secrets:ro depends_on: - vault-agent vault-agent: image: hashicorp/vault:latest command: vault agent -config=/etc/vault-agent.hcl volumes: - secrets-vol:/run/secrets volumes: secrets-vol: driver: local driver_opts: type: tmpfs device: tmpfs
import json
from pathlib import Path def get_db_url(): secret = json.loads(Path("/run/secrets/database.json").read_text()) return f"postgres://{secret['username']}:{secret['password']}@{secret['host']}:{secret['port']}/{secret['dbname']}"
import json
from pathlib import Path def get_db_url(): secret = json.loads(Path("/run/secrets/database.json").read_text()) return f"postgres://{secret['username']}:{secret['password']}@{secret['host']}:{secret['port']}/{secret['dbname']}"
import json
from pathlib import Path def get_db_url(): secret = json.loads(Path("/run/secrets/database.json").read_text()) return f"postgres://{secret['username']}:{secret['password']}@{secret['host']}:{secret['port']}/{secret['dbname']}"
# Vault database secrets engine config
resource "vault_database_secret_backend_role" "api_db" { name = "api-readonly" backend = "database" creation_statements = [ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" ] default_ttl = "24h" max_ttl = "48h"
}
# Vault database secrets engine config
resource "vault_database_secret_backend_role" "api_db" { name = "api-readonly" backend = "database" creation_statements = [ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" ] default_ttl = "24h" max_ttl = "48h"
}
# Vault database secrets engine config
resource "vault_database_secret_backend_role" "api_db" { name = "api-readonly" backend = "database" creation_statements = [ "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';", "GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" ] default_ttl = "24h" max_ttl = "48h"
}
from watchdog.observers import Observer
from watchdog.events import FileModifiedEvent class SecretReloader: def on_modified(self, event): if event.src_path == "/run/secrets/database.json": self.reconnect_database()
from watchdog.observers import Observer
from watchdog.events import FileModifiedEvent class SecretReloader: def on_modified(self, event): if event.src_path == "/run/secrets/database.json": self.reconnect_database()
from watchdog.observers import Observer
from watchdog.events import FileModifiedEvent class SecretReloader: def on_modified(self, event): if event.src_path == "/run/secrets/database.json": self.reconnect_database()
# .pre-commit-config.yaml
repos: - repo: https://github.com/trufflesecurity/trufflehog rev: v3.63.0 hooks: - id: trufflehog entry: trufflehog git file://. --only-verified --fail
# .pre-commit-config.yaml
repos: - repo: https://github.com/trufflesecurity/trufflehog rev: v3.63.0 hooks: - id: trufflehog entry: trufflehog git file://. --only-verified --fail
# .pre-commit-config.yaml
repos: - repo: https://github.com/trufflesecurity/trufflehog rev: v3.63.0 hooks: - id: trufflehog entry: trufflehog git file://. --only-verified --fail
# vault-agent cache configuration
cache { use_auto_auth_token = true
} listener "tcp" { address = "127.0.0.1:8200" tls_disable = true
}
# vault-agent cache configuration
cache { use_auto_auth_token = true
} listener "tcp" { address = "127.0.0.1:8200" tls_disable = true
}
# vault-agent cache configuration
cache { use_auto_auth_token = true
} listener "tcp" { address = "127.0.0.1:8200" tls_disable = true
}
[AWS services] → Vault (central) ← [GCP services] ↑ [Azure services]
[AWS services] → Vault (central) ← [GCP services] ↑ [Azure services]
[AWS services] → Vault (central) ← [GCP services] ↑ [Azure services] - AWS: Use Secrets Manager + IAM roles (not env vars, not Parameter Store for secrets)
- GCP: Use Secret Manager + Workload Identity
- Azure: Use Key Vault + Managed Identities - Pre-commit: trufflehog scans every commit before it's pushed
- CI: gitleaks runs on every PR
- Runtime: a log scanner watches Loki for patterns matching credentials - Vault OSS: Free. Runs on a single VM.
- Vault Enterprise (HA + namespaces): $0.03/hour per node
- AWS Secrets Manager: $0.40/secret/month + $0.05 per 10K API calls
- Our setup (Vault OSS + 1 VM): ~$20/month total - CI/CD Pipeline Optimization — securing secrets in fast CI pipelines
- Multi-Cloud Strategy Pitfalls — why cross-cloud secret management is one of the hidden costs
- Self-Hosted LLMs vs API — securing API keys and model credentials at scale