共计 13784 个字符,预计需要花费 35 分钟才能阅读完成。
在之前的文章中(点击此处查看上一篇文章),咱们理解了如何辨认蕴含密钥的文件,将密钥增加到 .gitignore
,通过 git-secret
进行加密,以及将加密文件提交到存储库。在本篇文章中,将带你理解如何在 Docker 容器中设置 git-secret
和 gpg
,通过 Makefile recipe 为不同的场景创立工作流。
Makefile Adjustment
将 git-secret
和 gpg
指令增加到 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="[email protected]" 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="[email protected]" 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 hook 主动执行此操作,不过要留神笼罩本地机密文件的危险哦。
代码审查和合并抵触
因为无奈对加密文件进行很好的辨别,因而当波及秘密时代码审查变得更加艰难。这是能够尝试应用 GitLab 进行审查,首先查看 .gitsecret/paths/mapping.cfg
文件的差别,在 UI 中查看哪些文件已更改。
此外,能够依据以下步骤来查看:
- 查看
main
分支。 - 通过
git secret reveal -f
解密文件 - 查看
feature-branch
. - 运行
git secret changes
来查看main
的解密文件和feature-branch
中加密文件之间的差别。
当多个团队成员须要同时批改不同分支上的机密文件时,状况会更加简单一些,因为 Git 无奈智能解决增量更新。
本地 git-secret 和 gpg 设置
当团队的所有人员将 git-secret
装置在本地,并且应用他们本人的 gpg
密钥,这也意味着团队的老本会随之减少,起因如下:
-
新退出开发团队的人员须要:
- 本地装置
git-secret
(*) - 在本地装置和设置
gpg
(*) - 创立
gpg
密钥对
- 本地装置
- 必须由所有其余团队成员 (*) 增加公钥。
- 必须通过增加密钥的用户
git secret tell
。 - 秘密须要从新加密。
对于来到团队的人员:
- 所有其余团队成员(*) 都须要删除公钥。
- 通过
git secret killperson
删除密钥的用户。 - 秘密须要从新加密。
另外,须要确保 git-secret
和gpg
版本放弃最新,防止遇到任何兼容性问题。作为代替计划,也能够通过 Docker 解决,而上述步骤中标注(*) 则能够省去,也就是不须要设置本地的 git-secret
和gpg
。
为了更加便捷,将存储库中每个开发人员的公共 gpg
密钥放在 .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
上述操作须要在容器启动后运行一次。
场景
先假如以下这些条件:
- 已查看过 Git 存储库。
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.*
gpg 密钥的初始设置
可怜的是,我没有找到通过 make
和docker
创立和导出 gpg
密钥的办法。你须要交互式地运行这些命令,或者传递一个带换行的字符串给它。这两件事在 make
和docker
中都简单得可怕。因而,你须要登录到应用程序的容器中,并在那里间接运行这些命令。这不是很简略,但无论如何,这只须要在一个新的开发人员入职时做一次。
密钥导出到 secret.gpg
,公钥导出到 gp.dev/gpg-keys/alice-public.gpg
。
# start the docker setup
make docker-up
# log into the container ('winpty' is only required on Windows)
winpty docker exec -ti dofroscra_local-application-1 bash
# export key pair
name="Alice Doe"
email="[email protected]"
gpg --batch --gen-key < .dev/gpg-keys/alice-public.gpg
$ make docker-up
ENV=local TAG=latest DOCKER_REGISTRY=docker.io DOCKER_NAMESPACE=dofroscra APP_USER_NAME=application APP_GROUP_NAME=application docker compose -p dofroscra_local --env-file ./.docker/.env -f ./.docker/docker-compose/docker-compose.yml -f ./.docker/docker-compose/docker-compose.local.yml up -d
Container dofroscra_local-application-1 Created
...
Container dofroscra_local-application-1 Started
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
...
95f740607586 dofroscra/application-local:latest "/usr/sbin/sshd -D" 21 minutes ago Up 21 minutes 0.0.0.0:2222->22/tcp dofroscra_local-application-1
$ winpty docker exec -ti dofroscra_local-application-1 bash
root:/var/www/app# name="Alice Doe"
root:/var/www/app# email="[email protected]"
gpg --batch --gen-key < 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: directory '/root/.gnupg' created
gpg: keybox '/root/.gnupg/pubring.kbx' created
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key BBBE654440E720C1 marked as ultimately trusted
gpg: directory '/root/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/root/.gnupg/openpgp-revocs.d/225C736E0E70AC222C072B70BBBE654440E720C1.rev'
root:/var/www/app# gpg --output secret.gpg --armor --export-secret-key $email
root:/var/www/app# head secret.gpg
-----BEGIN PGP PRIVATE KEY BLOCK-----
lQOYBGJD+bwBCADBGKySV5PINc5MmQB3PNvCG7Oa1VMBO8XJdivIOSw7ykv55PRP
3g3R+ERd1Ss5gd5KAxLc1tt6PHGSPTypUJjCng2plwD8Jy5A/cC6o2x8yubOslLa
x1EC9fpcxUYUNXZavtEr+ylOaTaRz6qwSabsAgkg2NZ0ey/QKmFOZvhL8NlK9lTI
GgZPTiqPCsr7hiNg0WRbT5h8nTmfpl/DdTgwfPsDn5Hn0TEMa79WsrPnnq16jsq0
Uusuw3tOmdSdYnT8j7m1cpgcSj0hRF1eh4GVE0o62GqeLTWW9mfpcuv7n6mWaCB8
DCH6H238gwUriq/aboegcuBktlvSY21q/MIXABEBAAEAB/wK/M2buX+vavRgDRgR
hjUrsJTXO3VGLYcIetYXRhLmHLxBriKtcBa8OxLKKL5AFEuNourOBdcmTPiEwuxH
5s39IQOTrK6B1UmUqXvFLasXghorv8o8KGRL4ABM4Bgn6o+KBAVLVIwvVIhQ4rlf
root:/var/www/app# gpg --armor --export $email > .dev/gpg-keys/alice-public.gpg
root:/var/www/app# head .dev/gpg-keys/alice-public.gpg
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBGJD+bwBCADBGKySV5PINc5MmQB3PNvCG7Oa1VMBO8XJdivIOSw7ykv55PRP
3g3R+ERd1Ss5gd5KAxLc1tt6PHGSPTypUJjCng2plwD8Jy5A/cC6o2x8yubOslLa
x1EC9fpcxUYUNXZavtEr+ylOaTaRz6qwSabsAgkg2NZ0ey/QKmFOZvhL8NlK9lTI
GgZPTiqPCsr7hiNg0WRbT5h8nTmfpl/DdTgwfPsDn5Hn0TEMa79WsrPnnq16jsq0
Uusuw3tOmdSdYnT8j7m1cpgcSj0hRF1eh4GVE0o62GqeLTWW9mfpcuv7n6mWaCB8
DCH6H238gwUriq/aboegcuBktlvSY21q/MIXABEBAAG0HUFsaWNlIERvZSA8YWxp
Y2VAZXhhbXBsZS5jb20+iQFOBBMBCgA4FiEEIlxzbg5wrCIsBytwu75lREDnIMEF
AmJD+bwCGy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQu75lREDnIMEN4Af+
至此 [email protected]
就有了一个新秘密和私钥,将其导出到 secret.gpg
。.dev/gpg-keys/alice-public.gpg
。剩下的命令当初能够间接在application
容器外的主机上运行。
git-secret 的初始设置
当初来将 git-secret
引入一个新的代码库,而后运行以下命令。
初始化 git-secret
:
make secret-init$ make secret-init
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="init";
git-secret: init created: '/var/www/app/.gitsecret/'
利用 gpg
对共享目录进行修复:
$ make secret-init-gpg-socket-config$ make secret-init-gpg-socket-config
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
容器启动后初始化 gpg
重启容器后,须要初始化 gpg
也就是导入公钥 .dev/gpg-keys/*
和导入私钥 Secret.gpg
,不然就无奈对文件进行加密和解密。
make gpg-init$ make gpg-init
"C:/Program Files/Git/mingw64/bin/make" -s gpg-import GPG_KEY_FILES="secret.gpg"
gpg: directory '/home/application/.gnupg' created
gpg: keybox '/home/application/.gnupg/pubring.kbx' created
gpg: /home/application/.gnupg/trustdb.gpg: trustdb created
gpg: key BBBE654440E720C1: public key "Alice Doe <[email protected]>" imported
gpg: key BBBE654440E720C1: secret key imported
gpg: Total number processed: 1
gpg: imported: 1
gpg: secret keys read: 1
gpg: secret keys imported: 1
"C:/Program Files/Git/mingw64/bin/make" -s gpg-import GPG_KEY_FILES=".dev/gpg-keys/*"
gpg: key BBBE654440E720C1: "Alice Doe <[email protected]>" not changed
gpg: Total number processed: 1
gpg: unchanged: 1
增加新成员
接下来一起看看如何将新成员退出到 git-secret
make secret-add-user EMAIL="[email protected]"$ make secret-add-user EMAIL="[email protected]"
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="tell [email protected]"
git-secret: done. [email protected] added as user(s) who know the secret.
验证是否通过:
make secret-show-users$ make secret-show-users
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="whoknows"
[email protected]
增加和加密文件
来增加一个新的加密文件 secret_password.txt
,创立以下文件:
echo "my_new_secret_password" > secret_password.txt
将其增加到 .gitignore
echo "secret_password.txt" >> .gitignore
将其增加到 git-secret
make secret-add FILE="secret_password.txt"$ make secret-add FILE="secret_password.txt"
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="add secret_password.txt"
git-secret: 1 item(s) added.
加密所有文件:
make secret-encrypt$ make secret-encrypt
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="hide"
git-secret: done. 1 of 1 files are hidden.$ ls secret_password.txt.secret
secret_password.txt.secret
解密文件
首先移除 secret_password.txt
文件,请运行:
rm secret_password.txt$ rm secret_password.txt$ ls secret_password.txt
ls: cannot access 'secret_password.txt': No such file or directory
而后进行解密:
make secret-decrypt$ make secret-decrypt
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="reveal -f"
git-secret: done. 1 of 1 files are revealed.$ cat secret_password.txt
my_new_secret_password
留神:如果 gpg
密钥受密码保护(假如明码是 123456
),请运行以下命令:
make secret-decrypt-with-password GPG_PASSWORD=123456
此外,还能够将 GPG_PASSWORD
变量退出.make/.env
文件作为本地默认值,这样就不必每次都指定该值,而后能够简略地运行以下命令而不传递 GPG_PASSWORD
:
make secret-decrypt-with-password
删除文件
能够通过以下形式解密文件:移除之前增加的 secret-password.txt
make secret-remove FILE="secret_password.txt"$ make secret-remove FILE="secret_password.txt"
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="remove secret_password.txt"
git-secret: removed from index.
git-secret: ensure that files: [secret_password.txt] are now not ignored.
留神:这里既不会主动删除 secret_password.txt
文件,也不会主动删除 secret_password.txt.secret
文件
$ ls -l | grep secret_password.txt
-rw-r--r-- 1 Pascal 197121 3 月 31 日 19 日 14:03 secret_password.txt
-rw-r--r-- 1 Pascal 197121 358 3 月 31 日 14:02 secret_password.txt.secret
即便加密的 secret_password.txt 文件依然存在,也不会被解密:
$ make secret-decrypt
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="reveal -f"
git-secret: done. 0 of 0 files are revealed.
移除团队成员
移除团队成员须要通过以下步骤:
make secret-remove-user EMAIL="[email protected]"$ make secret-remove-user EMAIL="[email protected]"
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="killperson [email protected]"
git-secret: removed keys.
git-secret: now [[email protected]] do not have an access to the repository.
git-secret: make sure to hide the existing secrets again.
如果团队中还有其余成员留下,须要确保再次加密机密文件:
make secret-encrypt
如果该组已移除全副成员,git-secret
就会报错:
$ make secret-decrypt
"C:/Program Files/Git/mingw64/bin/make" -s git-secret ARGS="reveal -f"
git-secret: abort: no public keys for users found. run 'git secret tell [email protected]'.
make[1]: *** [.make/01-00-application-setup.mk:57: git-secret] Error 1
make: *** [.make/01-00-application-setup.mk:69: secret-decrypt] Error 2
祝贺你~当初你能够加密和解密机密文件,并存储在 Git 存储库中啦!