密钥管理
存储、轮换和交付密钥(API key、数据库密码、签名密钥)而不泄露。
为什么
泄露的数据库密码或 API key 是云账户接管最常见原因,泄露几乎总通过当时认为方便的向量: 提交到 git 的 .env、为快速测试硬编码的密钥、打印环境的 CI 日志、结对编程时 Slack 分享的 key。密钥管理关于让安全路径成为容易路径——密钥管理器(Vault、AWS Secrets Manager、Doppler)运行时注入密钥,开发者永不碰原始密钥永无理由提交它们。泄露代价灾难性(账户接管、数据泄露、合规违规),预防代价是几小时设置永远回本。
何时使用
第一个密钥存在前就设好密钥管理器——补建痛苦因密钥已散到 .env、CI 变量、Slack。任何泄露疑似时立即轮换所有密钥。
如何做
1. 选密钥管理器使其成唯一密钥源 - 云: AWS Secrets Manager / Parameter Store、GCP Secret Manager、Azure Key Vault - 自托管: HashiCorp Vault、Doppler、Infisical - 管理器是唯一源;.env 仅本地开发且 gitignore 2. 运行时注入密钥,绝不烤进镜像或提交 - 容器: 启动时从管理器读,设为进程环境变量 - CI: 用 OIDC 联合假设角色取密钥,绝不存 CI 变量 - 本地开发: .env.local(gitignore)或 doppler run -- npm run dev 3. 持续扫泄露密钥 - 每次提交(pre-commit 钩子)和每个 PR 跑 gitleaks 或 TruffleHog - 启用 GitHub 密钥扫描 + push protection(提交前阻止落地) - git 历史中发现密钥立即轮换——别只删文件 4. 按计划轮换密钥和每次团队成员离职时 - 数据库密码: 每 90 天;API key: 按提供者策略每 30-180 天 - 员工离职: 24 小时内轮换他们有权的所有密钥 - 管理器支持处自动化轮换(AWS RDS 自动轮换) 5. 审计访问且绝不记密钥 - 记哈希或"***"非原始值;确保序列化器编辑密钥字段 - 审计谁何时访问哪个密钥;异常访问模式告警
示例
# .github/workflows/ci.yml — OIDC 联合,CI 中无长寿密钥
name: CI
on: [pull_request]
permissions:
id-token: write # OIDC 需要
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123:role/ci-deploy
aws-region: us-east-1
- name: 运行时取密钥
run: |
export DB_PASSWORD=$(aws secretsmanager get-secret-value --secret-id prod/db-password --query SecretString --output text)
npm test
# 数据库密码永不出现在 CI 日志、永不存为 GitHub secret,
# 且由 AWS 每 90 天自动轮换。
# Pre-commit 钩子: 提交前阻止密钥
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
# 若此钩子触发,提交被阻止。若密钥曾提交过则轮换——
# git 历史是永远的。常见问题
- ⚠把密钥存为 CI 提供者变量(GitHub Secrets)当安全——CI 变量打印时在日志可见、任何有仓库写权者可访问、不自动轮换,所以累积泄露。
- ⚠把 .env 提交到 git"只为团队有本地配置"——文件含生产数据库密码,现永远在 git 历史,后续提交删文件不从历史移除。
- ⚠为快速测试在源码硬编码 Stripe key 忘删——key 发布到生产,若是前端 key 则在公开 bundle 中,被扫 GitHub 或部署 JS 的攻击者发现。
- ⚠员工离职不轮换密钥——离职工程师本地 .env 仍有数据库密码,离职后可访问生产,这是真实内部威胁场景。
最佳实践
- ✓CI 中用 OIDC 联合使 CI 提供者处无长寿密钥——CI 作业通过短寿令牌假设云角色、从管理器取密钥、凭证分钟级过期。
- ✓启用 push protection(GitHub、GitLab)使含识别密钥模式的提交落地前被阻止——在源头止泄露,不到历史。
- ✓密钥管理器支持处自动化轮换(AWS RDS 自动轮换、Vault 动态密钥)——手动轮换会被忘,永不轮换的密钥是离泄露一步的密钥。
- ✓把 git 历史中发现的任何密钥当已泄露立即轮换——删文件不从历史移除,密钥提交那一刻起须假定已泄露。