背景
在软件开发过程中,敏感信息(如密码、API 密钥等)有时会意外地被提交到 Git 仓库中。随着项目的发展和历史提交记录的积累,清理这些敏感信息变得愈发困难,尤其是在无法修改生产密码的情况下。本文将介绍如何使用 git-filter-repo
工具安全地从 Git 历史记录中删除敏感信息,从而保护你的代码库安全并减少潜在的安全风险。
安装 git-filter-repo
git-filter-repo
是一个非常灵活的开源工具,可以从整个 Git 仓库历史中移除敏感信息和大文件(blobs),而不仅仅是最后的提交。它是 git-filter-branch
的推荐替代品。
首先,需要确保你的系统上安装过 Python。使用包管理器(如 pip)进行安装它是一种方便的方式。
下面可以安装 git-filter-repo
。你可以通过以下命令安装:
pip install git-filter-repo
前置准备与风险警告
评估影响:清理历史记录会影响整个代码库的历史,因此需要充分评估对项目和团队的影响。确保所有团队成员了解这次操作的重要性和必要性。
备份仓库:在进行任何历史修改之前,务必创建仓库的完整备份。(这样即使出问题了也还有救)可以通过以下命令克隆一个镜像仓库:
git clone 仓库地址
通知团队:清理敏感信息需要强制推送,这会覆盖远程仓库的历史记录。通知团队成员,确保他们了解即将进行的操作,并在清理操作完成前避免提交新的代码。
冻结代码库:在清理敏感信息期间,建议暂时冻结代码库,停止所有开发活动,避免冲突和数据丢失。
检查依赖和 CI/CD:确认所有依赖项和 CI/CD 管道不会因历史记录更改而受到影响。确保在清理后测试和部署流程仍能正常运行。
使用 git-filter-repo 删除敏感信息
以下是使用 git-filter-repo
删除敏感信息的关键步骤:
1.编写replacements.txt
可以放到电脑的任意位置,比如我是mac电脑,放在了/Users/admin/data/20240802目录下面
这个文件将列出你需要替换的敏感信息。格式如下:
password001 cigfkkdmgnl6jrfmbkqd0luaho54l9bbs==>process.env.SDK_KEY bob@split.io==>support@split.io password002==>[PASSWORD]
在 replacements.txt
文件中,每行包含一个敏感文本。你可以添加多条替换规则。
解释
原始内容 | 替换后内容 | 解释 |
---|---|---|
password001 | 完全移除 | 这一行表示 password001 将被从仓库历史中完全移除。 |
cigfkkdmgnl6jrfmbkqd0luaho54l9bbs | process.env.SDK_KEY | 这一行表示将 cigfkkdmgnl6jrfmbkqd0luaho54l9bbs 替换为 process.env.SDK_KEY。 |
bob@split.io | support@split.io | 这一行表示将 bob@split.io 替换为 support@split.io。 |
password002 | [PASSWORD] | 这一行表示将 password002 替换为 [PASSWORD]。 |
2.执行移除敏感数据命令
使用以下命令从整个 Git 仓库历史中移除敏感数据:
(PS:在执行接下来的命令时,一定要和团队取得联系,千万要小心!)
git filter-repo --replace-text /Users/admin/data/20240802/replacements.txt --replace-refs delete-no-add
解释
参数或选项 | 描述 |
---|---|
git filter-repo | 这是主要命令,用于启动 filter-repo 工具。 |
--replace-text /Users/admin/data/20240802/replacements.txt | 使用 /Users/admin/data/20240802/replacements.txt 文件中的替换规则来替换仓库中所有的文本(包括当前分支以及所有的历史提交)。这个文件包含一系列替换规则,可以参考上面的那个例子 |
--replace-refs delete-no-add | 这个选项用于替换引用,delete-no-add 表示删除旧引用但不添加新引用。 |
这条命令会根据 replacements.txt
文件中的规则替换历史记录中的敏感信息,并更新所有引用。
如果这条命令执行失败,它会提示你加上–force,那么可以改成这条命令
git filter-repo --replace-text /Users/admin/data/20240802/replacements.txt --replace-refs delete-no-add --force
切记,这个过程中,你当前项目里所有的replacements.txt里出现的文本都会被替换,不仅仅是你的历史提交记录,也包括你的当前的分支。所以如果你的这个密码如果与你的代码某部分重合,那么就会导致尴尬的情况:
比如你的有个密码叫Password。
而你有个类叫做PasswordService,正好命中这个密码
@Slf4j @Service @AllArgsConstructor public class PasswordService { }
那么它也会被替换成
@Slf4j @Service @AllArgsConstructor public class ***REMOVED***Service { }
这可能会导致你当前的项目无法运行。(所以要全局搜索一下REMOVED,看看是否要改回来)
另外一个比较好的做法是,在replacements.txt里增大匹配的难度,缩小替换的范围,比如,假设我们只是想修改application.yml里的配置,那其实可以在Password左侧加上其对应的key,那这样可以减少替换范围。
3.执行移除敏感文件命令
有些时候,如果你的某个文件整个都是敏感的。或者完全不想要某个文件的提交历史。(有可能是大文件)
你可以从提交历史中移除包含敏感数据的文件,可以使用以下命令:
(PS:在执行接下来的命令时,一定要和团队取得联系,千万要小心!)
git filter-repo --invert-paths --path <path-to-sensitive-file> --replace-refs delete-no-add
例如,如果你想移除文件 config.json
,命令如下:
git filter-repo --invert-paths --path config.json --replace-refs delete-no-add
命令部分 | 解释 |
---|---|
git filter-repo | 一个工具,用于重写Git存储库历史 |
–invert-paths | 反转路径选择,即选择所有不匹配指定路径的文件进行操作。 |
–path config.json | 指定路径 config.json ,在此命令中将与 --invert-paths 配合使用,即选择所有不包括 config.json 的文件。 |
–replace-refs delete-no-add | 删除所有对引用(如分支、标签等)的添加操作,而不添加新的引用。这意味着会删除历史记录中对引用的所有修改。 |
效果就是保留除了config.json以外的所有文件(等价于将config.json从所有提交中删除)
4.强制推送
当你执行完刚刚的惊心动魄的操作以后,你会发现的Git本地仓库不再关联远程仓库,比如你用下面这条命令检查一下
git remote -v
会发现没有输出,即为没有任何一个远端仓库与本地仓库相关,因此,此时需要重新执行下面这条命令,关联之前的远端仓库。
git remote add origin 仓库地址
强制推送到远程仓库:在本地清理完成后,你需要强制推送更改到远程仓库,以覆盖远程历史记录。
git push origin --force --all git push origin --force --tags
(PS:在执行这条命令时,一定要和团队取得联系,千万要小心!!!)
结论
通过上述步骤,你可以安全地从 Git 仓库中删除敏感信息,确保代码库的安全性。git-filter-repo
提供了一个强大而灵活的解决方案,使得清理 Git 历史变得更加容易和高效。
希望这篇指南能帮你更好地理解和使用 git-filter-repo
工具。如果有任何问题,欢迎在评论区讨论。