Env & Secrets Manager
Tier: POWERFUL
Category: Engineering
Domain: Security / DevOps / Configuration Management
Overview
Complete environment and secrets management workflow: .env file lifecycle across dev/staging/prod,
.env.example auto-generation, required-var validation, secret leak detection in git history, and
credential rotation playbook. Integrates with HashiCorp Vault, AWS SSM, 1Password CLI, and Doppler.
Core Capabilities
- - .env lifecycle — create, validate, sync across environments
- .env.example generation — strip values, preserve keys and comments
- Validation script — fail-fast on missing required vars at startup
- Secret leak detection — regex scan of git history and working tree
- Rotation workflow — detect → scope → rotate → deploy → verify
- Secret manager integrations — Vault KV v2, AWS SSM, 1Password, Doppler
When to Use
- - Setting up a new project — scaffold .env.example and validation
- Before every commit — scan for accidentally staged secrets
- Post-incident response — leaked credential rotation procedure
- Onboarding new developers — they need all vars, not just some
- Environment drift investigation — prod behaving differently from staging
.env File Structure
Canonical Layout
# .env.example — committed to git (no values)
# .env.local — developer machine (gitignored)
# .env.staging — CI/CD or secret manager reference
# .env.prod — never on disk; pulled from secret manager at runtime
# Application
APP_NAME=
APP_ENV= # dev | staging | prod
APP_PORT=3000 # default port if not set
APP_SECRET= # REQUIRED: JWT signing secret (min 32 chars)
APP_URL= # REQUIRED: public base URL
# Database
DATABASE_URL= # REQUIRED: full connection string
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
# Auth
AUTH_JWT_SECRET= # REQUIRED
AUTH_JWT_EXPIRY=3600 # seconds
AUTH_REFRESH_SECRET= # REQUIRED
# Third-party APIs
STRIPE_SECRET_KEY= # REQUIRED in prod
STRIPE_WEBHOOK_SECRET= # REQUIRED in prod
SENDGRID_API_KEY=
# Storage
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=eu-central-1
AWS_S3_BUCKET=
# Monitoring
SENTRY_DSN=
DD_API_KEY=
.gitignore Patterns
Add to your project's .gitignore:
CODEBLOCK1
.env.example Auto-Generation
CODEBLOCK2
Usage:
bash scripts/gen-env-example.sh .env .env.example
# Commit .env.example, never .env
git add .env.example
Required Variable Validation Script
→ See references/validation-detection-rotation.md for details
Secret Manager Integrations
HashiCorp Vault KV v2
CODEBLOCK4
AWS SSM Parameter Store
CODEBLOCK5
1Password CLI
CODEBLOCK6
Doppler
# Setup
doppler setup # interactive: select project + config
# Run any command with secrets injected
doppler run -- node server.js
doppler run -- npm run dev
# Export to .env (local dev only — never commit output)
doppler secrets download --no-file --format env > .env.local
# Pull specific secret
doppler secrets get DATABASE_URL --plain
# Sync to another environment
doppler secrets upload --project myapp --config staging < .env.staging.example
Environment Drift Detection
Check if staging and prod have the same set of keys (values may differ):
CODEBLOCK8
Common Pitfalls
- - Committing .env instead of .env.example — add
.env to .gitignore on day 1; use pre-commit hooks - Storing secrets in CI/CD logs — never
echo $SECRET; mask vars in CI settings - Rotating only one place — secrets often appear in Heroku, Vercel, Docker, K8s, CI — update ALL
- Forgetting to invalidate sessions after JWT secret rotation — all users will be logged out; communicate this
- Using .env.example with real values — example files are public; strip everything sensitive
- Not monitoring after rotation — watch audit logs for 24h after rotation to catch unauthorized old-credential use
- Weak secrets —
APP_SECRET=mysecret is not a secret. Use INLINECODE4
Best Practices
- 1. Secret manager is source of truth — .env files are for local dev only; never in prod
- Rotate on a schedule, not just after incidents — quarterly minimum for long-lived keys
- Principle of least privilege — each service gets its own API key with minimal permissions
- Audit access — log every secret read in Vault/SSM; alert on anomalous access
- Never log secrets — add log scrubbing middleware that redacts known secret patterns
- Use short-lived credentials — prefer OIDC/instance roles over long-lived access keys
- Separate secrets per environment — never share a key between dev and prod
- Document rotation runbooks — before an incident, not during one
环境与密钥管理器
层级: 强大
类别: 工程
领域: 安全 / DevOps / 配置管理
概述
完整的环境与密钥管理工作流程:涵盖开发/预发布/生产环境的 .env 文件生命周期管理、.env.example 自动生成、必需变量校验、Git 历史中的密钥泄露检测以及凭据轮换方案。支持与 HashiCorp Vault、AWS SSM、1Password CLI 和 Doppler 集成。
核心能力
- - .env 生命周期管理 — 创建、验证、跨环境同步
- .env.example 生成 — 剥离值,保留键名和注释
- 校验脚本 — 启动时对缺失必需变量快速失败
- 密钥泄露检测 — 对 Git 历史和工作树进行正则扫描
- 轮换工作流 — 检测 → 界定范围 → 轮换 → 部署 → 验证
- 密钥管理器集成 — Vault KV v2、AWS SSM、1Password、Doppler
使用场景
- - 搭建新项目 — 搭建 .env.example 和校验框架
- 每次提交前 — 扫描意外暂存的密钥
- 事件响应后 — 泄露凭据的轮换流程
- 新开发人员入职 — 他们需要所有变量,而不仅仅是部分
- 环境漂移调查 — 生产环境与预发布环境行为不一致
.env 文件结构
标准布局
bash
.env.example — 提交到 Git(不含值)
.env.local — 开发者机器(已加入 gitignore)
.env.staging — CI/CD 或密钥管理器引用
.env.prod — 绝不在磁盘上;运行时从密钥管理器拉取
应用
APP_NAME=
APP_ENV= # dev | staging | prod
APP_PORT=3000 # 未设置时的默认端口
APP_SECRET= # 必需:JWT 签名密钥(至少 32 字符)
APP_URL= # 必需:公共基础 URL
数据库
DATABASE_URL= # 必需:完整连接字符串
DATABASE
POOLMIN=2
DATABASE
POOLMAX=10
认证
AUTH
JWTSECRET= # 必需
AUTH
JWTEXPIRY=3600 # 秒
AUTH
REFRESHSECRET= # 必需
第三方 API
STRIPE
SECRETKEY= # 生产环境必需
STRIPE
WEBHOOKSECRET= # 生产环境必需
SENDGRID
APIKEY=
存储
AWS
ACCESSKEY_ID=
AWS
SECRETACCESS_KEY=
AWS_REGION=eu-central-1
AWS
S3BUCKET=
监控
SENTRY_DSN=
DD
APIKEY=
.gitignore 模式
添加到项目的 .gitignore 文件中:
gitignore
环境文件 — 绝不要提交这些文件
.env
.env.local
.env.development
.env.development.local
.env.test.local
.env.staging
.env.staging.local
.env.production
.env.production.local
.env.prod
.env.*.local
密钥文件
*.pem
*.key
*.p12
*.pfx
secrets.json
secrets.yaml
secrets.yml
credentials.json
service-account.json
AWS
.aws/credentials
Terraform 状态(可能包含密钥)
*.tfstate
*.tfstate.backup
.terraform/
Kubernetes 密钥
*-secret.yaml
*-secrets.yaml
.env.example 自动生成
bash
#!/bin/bash
scripts/gen-env-example.sh
从 .env 剥离值,保留键名、默认值和注释
INPUT=${1:-.env}
OUTPUT=${2:-.env.example}
if [ ! -f $INPUT ]; then
echo 错误:未找到 $INPUT
exit 1
fi
python3 - $INPUT $OUTPUT << PYEOF
import sys, re
input_file = sys.argv[1]
output_file = sys.argv[2]
lines = []
with open(input_file) as f:
for line in f:
stripped = line.rstrip(\n)
# 保留空行和注释原样
if stripped == or stripped.startswith(#):
lines.append(stripped)
continue
# 匹配 KEY=VALUE 或 KEY=VALUE
m = re.match(r^([A-Z][A-Z0-9])=(.)$, stripped)
if m:
key = m.group(1)
value = m.group(2).strip(\)
# 保留非敏感默认值(端口、区域、功能标志)
safe_defaults = re.compile(
r^(APPPORT|APPENV|APPNAME|AWSREGION|DATABASEPOOL|LOG_LEVEL|
rFEATURE|CACHETTL|RATELIMIT|PAGINATION|TIMEOUT),
re.I
)
sensitive = re.compile(
r(SECRET|KEY|TOKEN|PASSWORD|PASS|CREDENTIAL|DSN|AUTH|PRIVATE|CERT),
re.I
)
if safe_defaults.match(key) and value:
lines.append(f{key}={value} # 默认值)
else:
lines.append(f{key}=)
else:
lines.append(stripped)
with open(output_file, w) as f:
f.write(\n.join(lines) + \n)
print(f已从 {inputfile} 生成 {outputfile})
PYEOF
使用方法:
bash
bash scripts/gen-env-example.sh .env .env.example
提交 .env.example,绝不提交 .env
git add .env.example
必需变量校验脚本
→ 详见 references/validation-detection-rotation.md
密钥管理器集成
HashiCorp Vault KV v2
bash
设置
export VAULT_ADDR=https://vault.internal.company.com
export VAULT
TOKEN=$(vault login -method=oidc -format=json | jq -r .auth.clienttoken)
写入密钥
vault kv put secret/myapp/prod \
DATABASE_URL=postgres://user:pass@host/db \
APP_SECRET=$(openssl rand -base64 32)
将密钥读取到环境变量
eval $(vault kv get -format=json secret/myapp/prod | \
jq -r .data.data | to_entries[] | export \(.key)=\(.value))
在 CI/CD 中(GitHub Actions)
使用 vault-action:hashicorp/vault-action@v2
AWS SSM 参数存储
bash
写入(SecureString = 使用 KMS 加密)
aws ssm put-parameter \
--name /myapp/prod/DATABASE_URL \
--value postgres://... \
--type SecureString \
--key-id alias/myapp-secrets
将应用/环境的所有参数读取到 shell
eval $(aws ssm get-parameters-by-path \
--path /myapp/prod/ \
--with-decryption \
--query Parameters[*].[Name,Value] \
--output text | \
awk {split($1,a,/); print export a[length(a)] =\ $2 \})
在 Node.js 启动时
使用 @aws-sdk/client-ssm 在服务器启动前拉取参数
1Password CLI
bash
认证
eval $(op signin)
获取特定字段
op read op://MyVault/MyApp Prod/STRIPE
SECRETKEY
将项目中的所有字段导出为环境变量
op item get MyApp Prod --format json | \
jq -r .fields[] | select(.value != null) | export \(.label)=\\(.value)\ | \
grep -E ^export [A-Z_]+ | source /dev/stdin
.env 注入
op inject -i .env.tpl -o .env
.env.tpl 使用 {{ op://Vault/Item/field }} 语法
Doppler
bash
设置
doppler setup # 交互式:选择项目 + 配置
注入密钥运行任何命令
doppler run -- node server.js
doppler run -- npm run dev
导出到 .env(仅限本地开发 — 绝不要提交输出)
doppler secrets download --no-file --format env > .env.local
拉取特定密钥
doppler secrets get DATABASE_URL --plain
同步到另一个环境
doppler secrets upload --project myapp --config staging < .env.staging.example
环境漂移检测
检查