65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 git-secret 在仓库中加密敏感信息 [教程第六部分]

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2022 年 5 月 1 日

MIT

13分钟阅读

viewsIcon

6880

如何设置 git-secret 以将敏感信息直接存储在仓库中

git-secret example

供参考:本教程是下一部分 为 Docker 化 PHP 应用创建 CI 管道 的前奏,因为处理敏感信息是设置 CI 系统(以及稍后部署到生产环境)中的一个重要方面——但我认为它足够复杂,值得单独写一篇文章。

所有代码示例都可以在我的 Github 上的 Docker PHP 教程仓库 中公开获取。
您可以在 part-6-git-secret-encrypt-repository-docker 分支中找到本教程最终结果的分支。

已发布的 Docker PHP 教程部分

如果您想跟上教程,请订阅 RSS 源通过电子邮件,以便在下一部分发布时收到自动通知。:)

引言

处理敏感信息(密码、令牌、密钥文件等)在软件工程中与“命名事物”一样困难。一些需要考虑的方面:

  • 安全性至关重要——但高安全性通常伴随着高不便性。
    • 如果事情变得太复杂,人们就会寻找捷径……
  • 在团队中,共享某些敏感值通常是强制性的。
    • 所以,我们现在需要考虑安全地将敏感信息分发和更新给多个人。
  • 具体的敏感值通常取决于环境
    • 本质上很难“测试”甚至“审查”,因为这些值“按定义”与“您的机器”上的值与“生产环境”上的值不同。

事实上,已经有专门处理敏感信息的整个产品,例如 HashiCorp VaultAWS Secrets ManagerGCP Secret Manager。在项目中引入这些工具会带来一定的开销,因为它们是需要集成和维护的另一个服务。也许这对您的用例是正确的决定——也许有点过度。在本文结束时,您至少会了解一种进入门槛较低的替代方案。另请参阅末尾的 优点和缺点 部分以获取概览。

尽管通常不建议将敏感信息存储在仓库中,但我将在本教程中提出 exactly 这一点。

  • 识别包含敏感值的文件。
  • 确保它们已添加到 .gitignore
  • 通过 git-secret 加密它们。
  • 将加密文件提交到仓库。

最后,我们将能够执行

make secret-decrypt

来在代码库中显示敏感信息,必要时进行修改,然后运行

make secret-encrypt

再次加密它们,以便可以提交(并推送到远程仓库)。要查看实际效果,请检出分支 part-6-git-secret-encrypt-repository-docker 并运行以下命令。

# checkout the branch
git checkout part-6-git-secret-encrypt-repository-docker

# build and start the docker setup
make make-init
make docker-build
make docker-up

# "create" the secret key - the file "secret.gpg.example" would usually NOT live in the repo!
cp secret.gpg.example secret.gpg

# initialize gpg
make gpg-init

# ensure that the decrypted secret file does not exist
ls passwords.txt

# decrypt the secret file
make secret-decrypt

# show the content of the secret file
cat passwords.txt

工具

我们将把 gpggit-secret 设置在 php base 镜像中,以便这些工具可以在所有其他容器中使用。有关 Docker 镜像的详细解释,请参阅 2022 年从零开始为 PHP 8.1 应用构建 Docker

注意
以下所有命令都application 容器中执行。

提示
有关通过 din .bashrc 帮助程序方便地登录 Docker 容器,请参阅 Easy container access via din .bashrc helper

请注意,在使用主机系统和 Docker 之间共享的文件夹中的 git-secret 时存在一个注意事项。我将在 git-secret 目录和 gpg-agent 套接字 部分更详细地解释这一点(包括一种解决方法)。

gpg

gpgThe GNU Privacy Guard 的缩写,它是 OpenPGP 标准的开源实现。简而言之,它允许我们创建一个个人密钥对(类似于 SSH 密钥),其中包含一个私密密钥和一个公钥,公钥可以与您想要解密其消息的其他方共享。

gpg 安装

要安装它,我们可以简单地运行 apk add gnupg,并相应地更新 .docker/images/php/base/Dockerfile

# File: .docker/images/php/base/Dockerfile

RUN apk add --update --no-cache \
        bash \
        gnupg \
        make \
#...

gpg 用法

我只在这里介绍严格必需的 gpg 命令。有关更多信息,请参阅 git-secret 文档中的“使用 GPG”部分 和/或 如何使用 GPG 生成 PGP 密钥

创建 GPG 密钥对

我们需要 gpg 通过以下命令创建 gpg 密钥对

name="Pascal Landau"
email="pascal.landau@example.com"
gpg --batch --gen-key <<EOF
Key-Type: 1
Key-Length: 2048
Subkey-Type: 1
Subkey-Length: 2048
Name-Real: $name
Name-Email: $email
Expire-Date: 0
%no-protection
EOF

%no-protection 将创建一个没有密码的密钥,还可以参阅 此 Gist“以非交互方式创建 gpg 密钥”

输出

$ name="Pascal Landau"
$ email="pascal.landau@example.com"
$ gpg --batch --gen-key <<EOF
> Key-Type: 1
> Key-Length: 2048
> Subkey-Type: 1
> Subkey-Length: 2048
> Name-Real: $name
> Name-Email: $email
> Expire-Date: 0
> %no-protection
> EOF
gpg: key E1E734E00B611C26 marked as ultimately trusted
gpg: revocation certificate stored as '/root/.gnupg/opengpg-revocs.d/74082D81525723F5BF5B2099E1E734E00B611C26.rev'

您也可以在没有 --batch 标志的情况下运行 gpg --gen-key,以交互方式完成该过程。

导出、列出和导入私有 GPG 密钥

私钥可以通过以下方式导出

email="pascal.landau@example.com"
path="secret.gpg"
gpg --output "$path" --armor --export-secret-key "$email"

此私钥绝不能共享。!

看起来是这样的:

-----BEGIN PGP PRIVATE KEY BLOCK-----

lQOYBF7VVBwBCADo9un+SySu/InHSkPDpFVKuZXg/s4BbZmqFtYjvUUSoRAeSejv
G21nwttQGut+F+GdpDJL6W4pmLS31Kxpt6LCAxhID+PRYiJQ4k3inJfeUx7Ws339
XDPO3Rys+CmnZchcEgnbOfQlEqo51DMj6mRF2Ra/6svh7lqhrixGx1BaKn6VlHkC
...
ncIcHxNZt7eK644nWDn7j52HsRi+wcWsZ9mjkUgZLtyMPJNB5qlKQ18QgVdEAhuZ
xT3SieoBPd+tZikhu3BqyIifmLnxOJOjOIhbQrgFiblvzU1iOUOTOcSIB+7A
=YmRm
-----END PGP PRIVATE KEY BLOCK-----

可以列出所有私钥

gpg --list-secret-keys

输出

$ gpg --list-secret-keys
/root/.gnupg/pubring.kbx
------------------------
sec   rsa2048 2022-03-27 [SCEA]
      74082D81525723F5BF5B2099E1E734E00B611C26
uid           [ultimate] Pascal Landau <pascal.landau@example.com>
ssb   rsa2048 2022-03-27 [SEA] 

您可以通过以下方式导入私钥

path="secret.gpg"
gpg --import "$path"

并得到以下输出:

$ path="secret.gpg"
$ gpg --import "$path"
gpg: key E1E734E00B611C26: "Pascal Landau <pascal.landau@example.com>" not changed
gpg: key E1E734E00B611C26: secret key imported
gpg: Total number processed: 1
gpg:              unchanged: 1
gpg:       secret keys read: 1
gpg:  secret keys unchanged: 1
警告:如果私钥需要密码,您现在将被提示输入。我们可以使用 --batch --yes --pinentry-mode loopback 来规避提示。
path="secret.gpg"
gpg --import --batch --yes --pinentry-mode loopback "$path"

另请参阅 使用 GPG 的命令行密码输入。这样做,我们暂时不需要提供密码——但我们必须在尝试解密文件时传递它。

导出、列出和导入公钥 GPG 密钥

公钥可以通过以下方式导出public.gpg

email="pascal.landau@example.com"
path="public.gpg"
gpg --armor --export "$email" > "$path"

看起来是这样的:

-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBF7VVBwBCADo9un+SySu/InHSkPDpFVKuZXg/s4BbZmqFtYjvUUSoRAeSejv
G21nwttQGut+F+GdpDJL6W4pmLS31Kxpt6LCAxhID+PRYiJQ4k3inJfeUx7Ws339
...
3LLbK7Qxz0cV12K7B+n2ei466QAYXo03a7WlsPWn0JTFCsHoCOphjaVsncIcHxNZ
t7eK644nWDn7j52HsRi+wcWsZ9mjkUgZLtyMPJNB5qlKQ18QgVdEAhuZxT3SieoB
Pd+tZikhu3BqyIifmLnxOJOjOIhbQrgFiblvzU1iOUOTOcSIB+7A
=g0hF
-----END PGP PUBLIC KEY BLOCK-----

列出所有公钥

gpg --list-keys

输出

$ gpg --list-keys
/root/.gnupg/pubring.kbx
------------------------
pub   rsa2048 2022-03-27 [SCEA]
      74082D81525723F5BF5B2099E1E734E00B611C26
uid           [ultimate] Pascal Landau <pascal.landau@example.com>
sub   rsa2048 2022-03-27 [SEA]

公钥可以通过以下方式导入,与私钥类似:

path="public.gpg"
gpg --import "$path"

示例

$ gpg --import /var/www/app/public.gpg
gpg: key E1E734E00B611C26: "Pascal Landau <pascal.landau@example.com>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

git-secret

git-secret 的官方网站已经很好地介绍了该工具。简而言之,它允许我们声明某些文件为“敏感信息”,并通过 gpg 加密它们——使用所有受信任方的密钥。加密后的文件可以安全地直接存储在 git 仓库中,并在需要时解密

在本教程中,我使用的是 git-secret v0.4.0

$ git secret --version
0.4.0

git-secret 安装

适用于 Alpine 的安装说明如下:

sh -c "echo 'https://gitsecret.jfrog.io/artifactory/git-secret-apk/all/main'" >> 
/etc/apk/repositories
wget -O /etc/apk/keys/git-secret-apk.rsa.pub 
'https://gitsecret.jfrog.io/artifactory/api/security/keypair/public/repositories/git-secret-apk'
apk add --update --no-cache git-secret

我们将相应地更新 .docker/images/php/base/Dockerfile

# File: .docker/images/php/base/Dockerfile

# install git-secret
# @see https://git-secret.io/installation#alpine
ADD https://gitsecret.jfrog.io/artifactory/api/security/keypair/public/repositories/git-secret-apk /etc/apk/keys/git-secret-apk.rsa.pub

RUN echo "https://gitsecret.jfrog.io/artifactory/git-secret-apk/all/main" >> /etc/apk/repositories  && \
    apk add --update --no-cache \
        bash \
        git-secret \
        gnupg \
        make \
#...

git-secret 用法

初始化 git-secret

git-secret 通过以下命令进行初始化,在 git 仓库的根目录中运行

git secret init
$ git secret init
git-secret: init created: '/var/www/app/.gitsecret/'

我们只需要执行一次此操作,因为之后我们会将文件夹提交到 git。它包含以下文件:

$ git status | grep ".gitsecret"
        new file:   .gitsecret/keys/pubring.kbx
        new file:   .gitsecret/keys/pubring.kbx~
        new file:   .gitsecret/keys/trustdb.gpg
        new file:   .gitsecret/paths/mapping.cfg

pubring.kbx~ 文件(带有尾随波浪号 ~)只是一个临时文件,可以安全地忽略它。另请参阅 Can't find any docs about keyring.kbx~ file

git-secret 目录和 gpg-agent 套接字

要在在主机系统和 Docker 之间共享的目录中使用 git-secret,我们还需要运行以下命令:

tee .gitsecret/keys/S.gpg-agent <<EOF
%Assuan%
socket=/tmp/S.gpg-agent
EOF

tee .gitsecret/keys/S.gpg-agent.ssh <<EOF
%Assuan%
socket=/tmp/S.gpg-agent.ssh
EOF

tee .gitsecret/keys/gpg-agent.conf <<EOF
extra-socket /tmp/S.gpg-agent.extra
browser-socket /tmp/S.gpg-agent.browser
EOF

这是必需的,因为在代码库在主机系统和 Docker 容器之间共享的情况下使用 git-secret存在一个问题。我在 Github issue "gpg: can't connect to the agent: IPC connect call failed" error in docker alpine on shared volume 中解释了详细信息。

简而言之

  • gpg 使用 gpg-agent 来执行其任务,这两个工具通过 gpg-agent--home-directory 中创建的套接字进行通信。
  • 代理是通过 git-secret 使用的 gpg 命令隐式启动的,使用 .gitsecret/keys 目录作为 --home-directory
  • 由于 --home-directory 的位置与主机系统共享,因此套接字创建失败(可能仅是 Docker Desktop 的问题,请参阅 Github issue Support for sharing unix sockets 中的相关讨论)。

相应的错误消息是:

gpg: can't connect to the agent: IPC connect call failed

gpg-agent: error binding socket to '/var/www/app/.gitsecret/keys/S.gpg-agent': I/O error

此问题的解决方法可以在 此线程中找到:通过将其他 gpg 配置文件放置在 .gitsecret/keys 目录中来配置 gpg 使用不同的套接字位置。

S.gpg-agent

%Assuan%
socket=/tmp/S.gpg-agent

S.gpg-agent.ssh

%Assuan%
socket=/tmp/S.gpg-agent.ssh

gpg-agent.conf

extra-socket /tmp/S.gpg-agent.extra
browser-socket /tmp/S.gpg-agent.browser

添加、列出和删除用户

添加新用户,您必须先导入其公钥。然后运行:

email="pascal.landau@example.com"
git secret tell "$email"

在这种情况下,用户 pascal.landau@example.com 将能够解密敏感信息。

显示用户,请运行:

git secret whoknows
$ git secret whoknows
pascal.landau@example.com

要删除用户,请运行:

email="pascal.landau@example.com"
git secret killperson "$email"

供参考:此命令在 git-secret >= 0.5.0 中已重命名为 removeperson

$ git secret killperson pascal.landau@example.com
git-secret: removed keys.
git-secret: now [pascal.landau@example.com] do not have an access to the repository.
git-secret: make sure to hide the existing secrets again.

用户 pascal.landau@example.com 将不再能够解密敏感信息。

警告删除用户后必须重新加密敏感信息!

提醒:轮换加密的敏感信息

请注意,不仅您的敏感信息存储在 git 中,谁可以访问它们也是如此,也就是说,即使您删除了用户并重新加密了敏感信息,该用户仍然能够解密先前提交的敏感信息(当用户仍被添加时)。因此,删除用户后,您还需要轮换加密的敏感信息本身

但这难道不是系统的一个重大缺陷,使其普遍不适合使用 git-secret 吗?

在我看来:不是。

如果被删除的用户在任何时间点(无论它们存储在哪里)都可以访问敏感信息,他很有可能只是创建了一个本地副本或简单地“写了下来”。就安全性而言,git-secret 并没有带来任何“额外的缺点”。它只是非常清楚地表明您必须轮换敏感信息 ¯\_(ツ)_/¯

另请参阅 Hacker News 上关于 git-secret 的冗长讨论

添加、列出和删除要加密的文件

运行 git secret add [文件名...]加密文件。例如:

git secret add .env

如果 .env 未添加到 .gitignoregit-secret 将显示警告并自动添加它。

git-secret: these files are not in .gitignore: .env
git-secret: auto adding them to .env
git-secret: 1 item(s) added.

否则,文件将被添加而没有警告。

$ git secret add .env
git-secret: 1 item(s) added.

您只需要添加一次文件。它们随后存储在 .gitsecret/paths/mapping.cfg 中。

$ cat .gitsecret/paths/mapping.cfg
.env:505070fc20233cb426eac6a3414399d0f466710c993198b1088e897fdfbbb2d5

您也可以通过以下方式显示已添加的文件:

git secret list
$ git secret list
.env

警告:文件尚未加密!

如果您想删除一个文件以停止加密,请运行:

git secret remove .env

输出

$ git secret remove .env
git-secret: removed from index.
git-secret: ensure that files: [.env] are now not ignored.

加密文件

要实际加密文件,请运行:

git secret hide

输出

$ git secret hide
git-secret: done. 1 of 1 files are hidden.

加密的(二进制)文件存储在 $filename.secret,例如在这种情况下是 .env.secret

$ cat .env.secret
�☺♀♥�H~�B�Ӯ☺�"��▼♂F�►���l�Cs��S�@MHWs��e������{♣♫↕↓�L� ↕s�1�J$◄♥�;���dž֕�Za�����\u�ٲ& ¶��V�► ���6��
;<�d:��}ҨD%.�;��&��G����vWW�]>���߶��▲;D�+Rs�S→�Y!&J��۪8���ٔF��→f����*��$♠���&RC�8▼♂�☻z h��Z0M�T>

加密文件可供通过 git secret tell 添加的所有用户解密。这也意味着每次添加新用户时都需要再次运行此命令

解密文件

您可以通过以下方式解密文件

git secret reveal

输出

$ git secret reveal
File '/var/www/app/.env' exists. Overwrite? (y/N) y
git-secret: done. 1 of 1 files are revealed.
  • 文件将被解密,并将覆盖当前未加密的文件(如果它们已存在)。
    • 使用 -f 选项强制覆盖并以非交互方式运行。
  • 如果您只想检查加密文件的内容,可以使用 git secret cat $filename(例如,git secret cat .env)。

如果敏感 gpg 密钥已密码保护,您必须通过 -p 选项传递密码。例如,密码为 123456

git secret reveal -p 123456

显示加密和解密文件之间的差异

加密文件的一个问题是:您无法在远程工具的代码审查中审查它们。因此,为了了解已做出哪些更改,显示加密文件和解密文件之间的差异很有帮助。可以通过以下方式完成:

git secret changes

输出

$ echo "foo" >> .env
$ git secret changes
git-secret: changes in /var/www/app/.env:
--- /dev/fd/63
+++ /var/www/app/.env
@@ -34,3 +34,4 @@
 MAIL_ENCRYPTION=null
 MAIL_FROM_ADDRESS=null
 MAIL_FROM_NAME="${APP_NAME}"
+foo

注意输出底部的 +foo。它在第一行通过 echo "foo"> >> .env 添加。

Makefile 调整

由于我记不住 git-secretgpg 的所有命令,所以我已将它们添加到 Makefile 中,位于 .make/01-00-application-setup.mk

# File: .make/01-00-application-setup.mk

#...

# gpg

DEFAULT_SECRET_GPG_KEY?=secret.gpg
DEFAULT_PUBLIC_GPG_KEYS?=.dev/gpg-keys/*

.PHONY: gpg
gpg: ## Run gpg commands. Specify the command e.g. via ARGS="--list-keys"
    $(EXECUTE_IN_APPLICATION_CONTAINER) gpg $(ARGS)

.PHONY: gpg-export-public-key
gpg-export-public-key: ## Export a gpg public key 
e.g. via EMAIL="john.doe@example.com" PATH=".dev/gpg-keys/john-public.gpg"
    @$(if $(PATH),,$(error PATH is undefined))
    @$(if $(EMAIL),,$(error EMAIL is undefined))
    "$(MAKE)" -s gpg ARGS="gpg --armor --export $(EMAIL) > $(PATH)"

.PHONY: gpg-export-private-key
gpg-export-private-key: ## Export a gpg private key 
e.g. via EMAIL="john.doe@example.com" PATH="secret.gpg"
    @$(if $(PATH),,$(error PATH is undefined))
    @$(if $(EMAIL),,$(error EMAIL is undefined))
    "$(MAKE)" -s gpg ARGS="--output $(PATH) --armor --export-secret-key $(EMAIL)"

.PHONY: gpg-import
gpg-import: ## Import a gpg key file 
e.g. via GPG_KEY_FILES="/path/to/file /path/to/file2"
    @$(if $(GPG_KEY_FILES),,$(error GPG_KEY_FILES is undefined))
    "$(MAKE)" -s gpg ARGS="--import --batch --yes 
    --pinentry-mode loopback $(GPG_KEY_FILES)"

.PHONY: gpg-import-default-secret-key
gpg-import-default-secret-key: ## Import the default secret key
    "$(MAKE)" -s gpg-import GPG_KEY_FILES="$(DEFAULT_SECRET_GPG_KEY)"

.PHONY: gpg-import-default-public-keys
gpg-import-default-public-keys: ## Import the default public keys
    "$(MAKE)" -s gpg-import GPG_KEY_FILES="$(DEFAULT_PUBLIC_GPG_KEYS)" 

.PHONY: gpg-init
gpg-init: gpg-import-default-secret-key 
gpg-import-default-public-keys ## Initialize gpg in the container, 
                               ## i.e. import all public and private keys

# git-secret

.PHONY: git-secret
git-secret: ## Run git-secret commands. Specify the command e.g. via ARGS="hide"
    $(EXECUTE_IN_APPLICATION_CONTAINER) git-secret $(ARGS)

.PHONY: secret-init
secret-init: ## Initialize git-secret in the repository via `git-secret init`
    "$(MAKE)" -s git-secret ARGS="init"

.PHONY: secret-init-gpg-socket-config
secret-init-gpg-socket-config: ## Initialize the config files to change the 
                               ## gpg socket locations
    echo "%Assuan%" > .gitsecret/keys/S.gpg-agent
    echo "socket=/tmp/S.gpg-agent" >> .gitsecret/keys/S.gpg-agent
    echo "%Assuan%" > .gitsecret/keys/S.gpg-agent.ssh
    echo "socket=/tmp/S.gpg-agent.ssh" >> .gitsecret/keys/S.gpg-agent.ssh
    echo "extra-socket /tmp/S.gpg-agent.extra" > .gitsecret/keys/gpg-agent.conf
    echo "browser-socket /tmp/S.gpg-agent.browser" >> .gitsecret/keys/gpg-agent.conf

.PHONY: secret-encrypt
secret-encrypt: ## Decrypt secret files via `git-secret hide`
    "$(MAKE)" -s git-secret ARGS="hide"

.PHONY: secret-decrypt
secret-decrypt: ## Decrypt secret files via `git-secret reveal -f`
    "$(MAKE)" -s git-secret ARGS="reveal -f" 

.PHONY: secret-decrypt-with-password
secret-decrypt-with-password: ## Decrypt secret files using a password 
                              ## for gpg via `git-secret reveal -f -p $(GPG_PASSWORD)`
    @$(if $(GPG_PASSWORD),,$(error GPG_PASSWORD is undefined))
    "$(MAKE)" -s git-secret ARGS="reveal -f -p $(GPG_PASSWORD)" 

.PHONY: secret-add
secret-add: ## Add a file to git secret via `git-secret add $FILE`
    @$(if $(FILE),,$(error FILE is undefined))
    "$(MAKE)" -s git-secret ARGS="add $(FILE)"

.PHONY: secret-cat
secret-cat: ## Show the contents of file to git secret via `git-secret cat $FILE`
    @$(if $(FILE),,$(error FILE is undefined))
    "$(MAKE)" -s git-secret ARGS="cat $(FILE)"

.PHONY: secret-list
secret-list: ## List all files added to git secret `git-secret list`
    "$(MAKE)" -s git-secret ARGS="list"

.PHONY: secret-remove
secret-remove: ## Remove a file from git secret via `git-secret remove $FILE`
    @$(if $(FILE),,$(error FILE is undefined))
    "$(MAKE)" -s git-secret ARGS="remove $(FILE)"

.PHONY: secret-add-user
secret-add-user: ## Remove a user from git secret via `git-secret tell $EMAIL`
    @$(if $(EMAIL),,$(error EMAIL is undefined))
    "$(MAKE)" -s git-secret ARGS="tell $(EMAIL)"

.PHONY: secret-show-users
secret-show-users: ## Show all users that have access to git secret 
                   ## via `git-secret whoknows`
    "$(MAKE)" -s git-secret ARGS="whoknows"

.PHONY: secret-remove-user
secret-remove-user: ## Remove a user from git secret via `git-secret killperson $EMAIL`
    @$(if $(EMAIL),,$(error EMAIL is undefined))
    "$(MAKE)" -s git-secret ARGS="killperson $(EMAIL)"

.PHONY: secret-diff
secret-diff: ## Show the diff between the content of encrypted and 
             ## decrypted files via `git-secret changes`
    "$(MAKE)" -s git-secret ARGS="changes"

工作流

使用 git-secret 操作非常直接。

  • 初始化 git-secret
  • 添加所有用户。
  • 添加所有敏感文件,并确保它们通过 .gitignore 被忽略。
  • 加密文件。
  • 像“任何其他文件”一样提交加密文件。
  • 如果其他团队成员对文件进行了任何更改
    • => 解密以获取最新的文件。
  • 如果您需要进行任何修改
    • => 对解密的文件进行修改,然后再次加密它们。

但是:魔鬼在细节中。 流程挑战部分解释了一些我们遇到的陷阱,而 场景部分提供了一些常见场景的具体示例。

流程挑战

从流程的角度来看,我们遇到了一些挑战,我想在此提及——包括我们如何处理它们。

更新敏感信息

更新敏感信息时,您必须确保始终先解密文件,以避免使用您本地可能仍拥有的“过时”文件。我通常会检出最新的 main 分支并运行 git secret reveal 以获取最新版本的敏感文件。您也可以使用 post-merge git 钩子来自动执行此操作,但我个人不想冒意外覆盖本地敏感文件的风险。

代码审查和合并冲突

由于加密文件无法有意义地进行 diff,因此涉及敏感信息的代码审查变得更加困难。我们使用 Gitlab 进行审查,我通常会先查看 .gitsecret/paths/mapping.cfg 文件的 diff,以便直接在 UI 中看到“哪些文件已更改”。

此外,我还会

  • 检出 main 分支。
  • 通过 git secret reveal -f 解密敏感信息。
  • 检出 feature-branch
  • 运行 git secret changes 来查看来自 main 的解密文件与来自 feature-branch 的加密文件之间的差异。

当多个团队成员需要在不同分支上同时修改敏感文件时,情况会变得更加复杂,因为无法比较加密文件——即 git 无法智能地处理增量更新。唯一的解决办法是协调拉取请求,即先合并第一个,更新第二个的敏感信息,然后再合并第二个。

幸运的是,到目前为止这种情况只发生过很少。

本地 git-secret 和 gpg 设置

目前,我们团队中的所有开发人员都在本地安装了 git-secret(而不是通过 Docker 使用它),并使用他们自己的 gpg 密钥。

这意味着更多的入职开销,因为

  • 新开发人员必须
    • 在本地安装 git-secret (*)
    • 在本地安装和设置 gpg (*)
    • 创建一个 gpg 密钥对。
  • 公钥必须由其他每个团队成员添加 (*)。
  • 必须通过 git secret tell 添加密钥用户。
  • 必须重新加密敏感信息。

对于离职

  • 公钥必须由其他每个团队成员删除 (*)。
  • 必须通过 git secret killperson 删除密钥用户。
  • 必须重新加密敏感信息。

此外,我们需要确保 git-secretgpg 的版本对每个人都保持最新,以避免任何兼容性问题。

作为替代方案,我目前更倾向于通过 Docker 处理所有事情(如本教程所示)。所有标记为 (*) 的步骤都将变得多余,即无需在本地设置 git-secretgpg

但是这种方法也有一些缺点,因为

  • 私钥和所有公钥都必须在每次启动容器时导入
  • 每个开发人员都需要将他们的私有 gpg 密钥“放入代码库中”(被 .gitignore 忽略),以便它可以与 docker 共享并由 gpg(在 Docker 中)导入。另一种选择是使用一个在团队内共享的私钥——这感觉非常糟糕 :P。

为了使这一点更方便一些,我们将每个开发人员的公钥放在仓库的 .dev/gpg-keys/ 目录下,私钥必须命名为 secret.gpg 并放在代码库的根目录中

在此设置中,secret.gpg 也必须添加到 .gitignore 文件中。

# File: .gitignore
#...
vendor/
secret.gpg

现在可以使用 make 目标来简化导入。

# gpg

DEFAULT_SECRET_GPG_KEY?=secret.gpg
DEFAULT_PUBLIC_GPG_KEYS?=.dev/gpg-keys/*

.PHONY: gpg
gpg: ## Run gpg commands. Specify the command e.g. via ARGS="--list-keys"
    $(EXECUTE_IN_APPLICATION_CONTAINER) gpg $(ARGS)

.PHONY: gpg-import
gpg-import: ## Import a gpg key file
            ## e.g. via GPG_KEY_FILES="/path/to/file /path/to/file2"
    @$(if $(GPG_KEY_FILES),,$(error GPG_KEY_FILES is undefined))
    "$(MAKE)" -s gpg ARGS="--import --batch --yes 
              --pinentry-mode loopback $(GPG_KEY_FILES)"

.PHONY: gpg-import-default-secret-key
gpg-import-default-secret-key: ## Import the default secret key
    "$(MAKE)" -s gpg-import GPG_KEY_FILES="$(DEFAULT_SECRET_GPG_KEY)"

.PHONY: gpg-import-default-public-keys
gpg-import-default-public-keys: ## Import the default public keys
    "$(MAKE)" -s gpg-import GPG_KEY_FILES="$(DEFAULT_PUBLIC_GPG_KEYS)" 

.PHONY: gpg-init
gpg-init: gpg-import-default-secret-key gpg-import-default-public-keys ## Initialize 
              ## gpg in the container, i.e. import all public and private keys

现在可以通过以下方式处理“一切”

make gpg-init

在启动容器后,只需运行一次。

场景

场景假设以下先决条件:

  • 您已检出分支 part-6-git-secret-encrypt-repository-docker
    git checkout part-6-git-secret-encrypt-repository-docker

    并且没有正在运行的 Docker 容器。

    make docker-down
  • 您已删除现有的 git-secret 文件夹、.dev/gpg-keys 中的密钥、secret.gpg 密钥和 passwords.* 文件。
    rm -rf .gitsecret/ .dev/gpg-keys/* secret.gpg passwords.*


由于技术限制,本文最多为 40000 个字符。请在 Use git-secret to encrypt secrets in the repository [Tutorial Part 6] 阅读完整内容。

© . All rights reserved.