在使用 gitleaks 扫描仓库时意外发现,项目早期的若干提交中包含了一些 Secret Key。整改时,大多数密钥可以通过吊销并重新生成解决,但阿里云云市场中的某个服务的 API 密钥既无法吊销也无法重置,只能设法彻底清理仓库历史中的敏感信息。

本文主要参考 GitHub 官方文档 Removing sensitive data from a repository - GitHub Docs,以下示例均以 GitHub 仓库为背景。

整个清理流程包括以下三个步骤:

  1. 使用 git-filter-repo 在本地重写存储库
  2. 从 GitHub 中完全删除数据
  3. 与同事协调清理现存的其他克隆

风险提示

由于清理过程会从引入敏感信息的 commit 开始重建 Git 历史,因此会产生一些副作用(详见上述官方文档)。这些副作用包括但不限于:分支保护规则会被关闭、其他协作者的工作内容可能丢失、历史 PR 的 diff 信息失效等。

使用 git-filter-repo 在本地重写存储库

首先安装 git-filter-repo 工具:

brew install git-filter-repo

克隆仓库并进入目录:

git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY
cd YOUR-REPOSITORY

若要删除包含敏感信息的整个文件,执行以下命令:

git-filter-repo --sensitive-data-removal --invert-paths --path GIT-PATH

若要删除指定文本,需先准备一个敏感内容词表。词表支持正则表达式、glob 模式和指定替换后文本等配置1,之后执行清理:

git-filter-repo --sensitive-data-removal --replace-text ../passwords.txt

git-filter-repo 输出
git-filter-repo 输出

执行完成后,需要记录以下数据供下一步使用:

  • 输出中的 First Changed Commit

  • 输出中的 Orphaned LFS objects

  • 受影响的 PR ref 数量,可通过以下命令查看:

    grep -c '^refs/pull/.*/head$' .git/filter-repo/changed-refs
    

确认更改结果无误后,需先关闭 GitHub 分支保护规则,然后强制推送到远端:

git push --force --mirror origin

从 GitHub 中完全删除数据

通过 GitHub Support portal 向 GitHub 提交工单,需要提供以下信息:

  • 仓库的 owner 和 name
  • 上一步中收集的 First Changed Commit
  • 上一步中收集的受影响的 PR ref 数量
  • 上一步中收集的 Orphaned LFS objects

GitHub 官方人员会对受影响的分支引用和 LFS 文件进行清理。

与同事协调清理现存的其他克隆

所有该项目的协作者应该重新克隆项目,或者使用 rebase 方式进行 pull(而非 merge),避免将旧代码重新引入造成污染。

小结

完成上述步骤后,还需恢复之前禁用的分支保护规则。

整个过程并不算特别复杂,但对于大型项目而言,需要协调一个所有协作者都能配合的时间窗口,确保清理工作顺利完成。