第一原则:永远不要 commit 到 git

# 一秒钟泄露:
git add .env && git commit -m "config" && git push

哪怕仓库 private——历史一旦提交,就要按"已经泄露"处理。所有出现过的密钥立即作废 + 轮换

防护手段:

  • .gitignore.env *.pem *.key
  • pre-commit hookgitleaks
  • GitHub / GitLab 的 secret scanning 自动开

第二原则:知道自己有多少密钥

完整盘点一次:"我们有多少 secret?分别是谁、多少地方在用?"——多数公司答不出。

把所有 secret 编目(哪个服务、什么用途、何时创建、谁是 owner、上次轮换时间)——这是密钥管理的起点

工具谱

层级 工具
本地开发 direnv + .envrc.local(不进 git)
CI GitHub Actions Secrets / GitLab CI Variables
K8s K8s Secret(基础)/ Sealed Secrets / External Secrets Operator
应用运行时 HashiCorp Vault / AWS Secrets Manager / GCP Secret Manager / Azure Key Vault / 阿里 KMS
企业级 HashiCorp Vault Enterprise / CyberArk / 1Password Business

不需要全部都用——起步可以只是云商的 Secrets Manager + GitHub Secrets

短期凭据 > 长期凭据

长期凭据:access_key_id + secret_access_key(永远有效)
短期凭据:1 小时过期的 STS token / Workload Identity 自动签发

短期凭据的好处:

  • 泄露窗口小
  • 不需要"轮换"——本来就过期
  • 自动绑定 Workload Identity,权限审计清晰

云商方案:

  • AWS:IRSA(IAM Roles for Service Accounts)让 K8s Pod 直接拿 STS token
  • GCP:Workload Identity 把 K8s ServiceAccount 映射到 GCP Service Account
  • Azure:Workload Identity(原 Pod Identity 已废弃)
  • 阿里 / 腾讯:RAM Role / CAM Role for Pod

新项目优先用短期凭据。长期 access key 本身就是反模式。

轮换(Rotation)

  • 数据库密码 / API 凭据:定期轮换(年 / 季度)
  • TLS 证书:自动续签(Let's Encrypt / ACM 都自动)
  • 应用层 API key:每次 commit 检测;离职 / 怀疑泄露时立即轮换
  • 短期凭据:自动过期,无需手动

轮换的难点是"应用怎么平滑切换"——支持双密钥并存期:

T0:新密钥 K2 加进 secret store,应用同时接受 K1 + K2
T1:所有客户端切到 K2
T2:作废 K1

很多 secret store(Vault / Secrets Manager)支持"两个版本同时有效"+ 渐进切换。

加密 at-rest 与 in-transit

  • at-rest:磁盘上的数据加密(云盘加密、数据库 TDE、S3 SSE)
  • in-transit:传输中加密(TLS)

两者都是基础——不是"加分项"。云上几乎免费就能开,没理由不开。

几个常见坑

  • echo $TOKEN 进 CI 日志:log 里就是明文。CI 工具自动 mask 已声明的 secret,但 echo 后被处理过的字符串可能漏
  • secret 写进 K8s ConfigMap:K8s 区分 ConfigMap / Secret,不要混用
  • Docker image 里塞 secret:build 历史会留下来
  • shell history 里mysql -p mypassword——password 直接进 history。用 ~/.my.cnf--password-file
  • 同一个 key 多个用途:一处泄露全线作废

应用怎么读 secret

设计原则:注入到环境变量或文件里,应用代码不知道 secret store 存在。

# 反模式:应用直连 Vault
client = hvac.Client()
secret = client.secrets.kv.read("payment/api-key")

# 推荐:环境变量 / 文件,由编排层注入
api_key = os.environ["PAYMENT_API_KEY"]

注入工具:

  • K8s + ESO / Sealed Secrets
  • Vault Agent Injector(K8s mutating webhook)
  • 云商 SDK + Pod 启动 hook

应用代码与具体 secret 实现解耦——换 store 就不用改代码。

推荐阅读

下一篇:扩到镜像和依赖——软件供应链安全。