开源前的密钥治理:gitleaks + 历史清理 + 凭证轮换
云原生与交付30 阅读约 4 分钟
把几个一直私有的仓库开源时,我做的第一件事不是写 README,而是密钥治理。因为一旦推上公网,任何曾经提交过的密钥都等于公开。这篇复盘一次真实事故和完整的处置流程。
事故:开发用 env 里混进了真 AccessKey
准备开源部署仓库时,我在 .env.development 里发现一串阿里云 AccessKey(LTAI5t8D...)。它本该是「开发默认值」,却不知何时被填进了真实生产凭证,还跟着提交进了 git 历史。
这是个极典型的坑:开发配置文件被纳入版本控制,某次图方便填了真密钥,从此长在历史里。
三步处置
第一步:当前文件去敏
先把现有文件里的真凭证换成安全的本地默认值——开发环境本就该用本地 MinIO,不需要云凭证:
S3_ENDPOINT=http://minio:9000
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_BUCKET=andy-blog
S3_FORCE_PATH_STYLE=true
第二步:清理 git 历史
只改当前文件不够——密钥还躺在历史 commit 里,git log 一翻就有。我用 orphan 分支把历史压成一个干净的初始提交,物理上抹掉旧历史:
git checkout --orphan clean_main # 建一个没有历史的孤儿分支
git add -A
git commit -m "chore: initial public commit"
git branch -D main
git branch -m clean_main main
git push -f origin main # 强推覆盖远程
git reflog expire --expire=now --all # 清本地 reflog
git gc --prune=now # GC 掉悬空对象
之后再用 gitleaks 扫一遍,确认历史里再无密钥,并把它接进 CI 防复发:
# .github/workflows/gitleaks.yml —— 每次 push 自动扫密钥
- uses: gitleaks/gitleaks-action@v2
第三步(最关键):轮换凭证
这是最反直觉、也最重要的一条铁律:
凡是曾经进过版本控制的密钥,无论后来怎么清理,都必须当作已泄露来处理——去源头轮换它。
为什么?因为你无法保证它没被复制走:
- 仓库可能被人 clone、fork 过,本地副本里仍有旧历史;
- CI、备份、镜像缓存里可能留有残影;
- 你的「清理干净了」只是「在你能看到的地方干净了」。
git 历史清理消除的是继续暴露,但消除不了已经发生过的暴露。唯一能让旧密钥彻底失效的办法,是去阿里云控制台禁用旧 AccessKey、生成新的。新密钥只存进 .env.production.local(git 忽略,只在服务器上)。
把规则固化,别靠记性
事后我做了几件「让同类问题不再发生」的事:
.env.development只放假值,真密钥一律进 git 忽略的.local文件;- gitleaks 进 CI,每次 push 自动扫,把检测左移到提交时;
- env 分层固化:可入库的非敏感配置 vs 绝不入库的密钥,物理分文件。
小结
开源前的密钥治理是三步:当前文件去敏、git 历史清理、源头轮换凭证。其中轮换最关键也最容易被省略——很多人清完历史就以为安全了。记住那条铁律:进过版本控制的密钥就是泄露的密钥,清理只防继续暴露,轮换才真正止血。最后用 gitleaks + env 分层把规则固化进流程,别靠人的记性。





