Skip to main content

Secret Management — Secrets Never in Code

API keys, DB passwords, and certs must be fetched at runtime from a secrets manager — never in source code, env files, or container images.

When to use

  • Always — for any credential, API key, certificate, or signing key

Tradeoffs

  • Secrets manager is a runtime dependency (must be HA; startup fails if unavailable)
  • Rotation requires app support (connection re-initialization, graceful reload)
func loadSecret(ctx context.Context, secretID string) (string, error) {
client, err := secretsmanager.NewFromConfig(awsCfg)
if err != nil {
return "", fmt.Errorf("secrets manager unavailable: %w", err)
}
out, err := client.GetSecretValue(ctx, &secretsmanager.GetSecretValueInput{
SecretId: aws.String(secretID),
})
if err != nil {
// fail fast — no fallback to defaults
return "", fmt.Errorf("cannot load secret %s: %w", secretID, err)
}
return aws.ToString(out.SecretString), nil
}

// Call at startup; re-call on SIGHUP for rotation support
func main() {
dbPass, err := loadSecret(ctx, "prod/db/password")
if err != nil {
log.Fatal(err) // hard exit — do not proceed with empty secret
}
initDB(dbPass)
}

Gotcha: Rotating a secret and NOT restarting services that cached it in memory is a partial rotation. Automate the restart, or use dynamic short-lived secrets (Vault dynamic credentials) so rotation is continuous.