The fastest way to breach a cloud environment isn't an exploit — it's a credential someone left lying around. A database password in a .env file committed to a public repo, an API key baked into a container image, a cloud access key pasted into a CI variable and never rotated: these are the openings attackers look for first because they work. Secrets management isn't a single product you buy; it's a lifecycle you enforce. This guide walks that lifecycle — store, distribute, rotate, detect — and shows how it plays out on AWS, Azure, and GCP.
Stage 1: Store Secrets in a Purpose-Built Vault
The foundational rule: secrets live in a dedicated secrets manager, never in source code, container images, environment variables baked at build, or IaC state. Every major cloud ships one, and they share the same shape — encrypted storage, IAM-gated access, versioning, and audit logging:
- AWS — Secrets Manager (with rotation) or SSM Parameter Store (SecureString)
- Azure — Key Vault, with soft-delete and purge protection enabled
- GCP — Secret Manager
For multi-cloud or on-prem, HashiCorp Vault provides the same model with dynamic secrets that are generated on demand and expire automatically.
Stage 2: Distribute Without Creating New Secrets
The subtle failure is solving secret storage but then needing a secret to access the vault — you've just moved the problem. The fix is workload identity: let the platform prove who the workload is, so it can read from the vault with no bootstrap credential.
# Kubernetes: mount a vault secret via workload identity, no static creds
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: prod
spec:
refreshInterval: 1h
secretStoreRef:
name: gcp-secret-store # authenticates via Workload Identity
kind: SecretStore
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: prod-db-password
On AWS a Lambda or pod reads Secrets Manager through its execution role or IRSA; on Azure a workload reads Key Vault through a managed identity; on GCP a workload reads Secret Manager through Workload Identity. In every case there is no long-lived credential to leak.
Stage 3: Rotate Automatically
A secret that never changes is a secret that will eventually leak and stay valid. Enable automatic rotation where the platform supports it — Secrets Manager can rotate RDS credentials on a schedule using a rotation function, and Vault's dynamic secrets are inherently short-lived. For everything else, set a rotation cadence and, more importantly, make sure your application reads the secret fresh rather than caching it for the life of the process, so rotation doesn't cause outages.
# Turn on scheduled rotation for an AWS-managed database secret
aws secretsmanager rotate-secret \
--secret-id prod/orders/db \
--rotation-rules AutomaticallyAfterDays=30
Stage 4: Detect Secrets That Escaped the Process
No matter how good your process is, secrets leak — pasted into a chat, hardcoded in a hotfix, echoed into a log. You need detection in two places. In the pipeline: scan every commit and pull request for high-entropy strings and known credential formats, and fail the build so the secret never merges. In artifacts: scan container images and deployment bundles, because a secret can be baked in at build even when the source looks clean. When a real secret is found, revoke and rotate it — deleting the commit does not un-leak a credential that's already in Git history and possibly already scraped. Pipeline-native scanning through the Safeguard CLI is the enforcement point for this stage.
The Blind Spot: Infrastructure-as-Code State
One place secrets hide even in disciplined teams is Terraform state. When a resource like a database or a randomly generated password is created, its value is written to the state file in plaintext — regardless of how carefully you handle it in the configuration. Anyone who can read the state file can read the secret. Three habits close this gap: store state in an encrypted remote backend (S3 with SSE and bucket policies, an Azure Storage account with restricted access, or a GCS bucket with CMEK) rather than committing terraform.tfstate to Git; lock down read access to that backend as tightly as you would the vault itself; and prefer having Terraform reference a secret managed elsewhere over having it generate and store one. Treat the state file as a secret-bearing artifact, because it is one.
Secrets Management Checklist
| Stage | Control |
|---|---|
| Store | Secrets in a managed vault; none in code, images, env, or IaC state |
| Distribute | Workload identity to read the vault; no bootstrap credential |
| Rotate | Automatic rotation enabled; apps read fresh, not cached |
| Detect | Commit/PR + artifact secret scanning; revoke-and-rotate on any hit |
| Audit | Vault access logged; alerts on anomalous reads |
How Safeguard Helps
The most expensive secret is the one that reaches a shared branch or a shipped image, so Safeguard focuses on catching it before either happens. Its pipeline-native scanning, orchestrated through the Safeguard CLI, inspects commits and pull requests for hardcoded credentials, cloud keys, and high-entropy tokens, and can fail the build so the secret never merges. Its container image scanning catches secrets and credentials baked into image layers even when the source tree looks clean. Because IaC is a common place credentials hide — connection strings in Terraform, secrets in environment blocks — infrastructure-as-code scanning flags those too, tied to the exact line. Griffin, Safeguard's AI triage engine, distinguishes a live production credential from a test placeholder so your team acts on real leaks first. Teams comparing secret and dependency coverage across tools often review the Safeguard vs Snyk comparison.
Stop leaked secrets at the pull request — create a free account or read the documentation.