目录

How to Encrypt Git Files

为什么需要 crypt

在开发过程中经常会遇到一个问题:

怎么将敏感数据让特定的人获取到?

常用的解决方法如下:

  • 使用如 AWS 的 KMS, ParameterStore 等服务,给不同的用户以访问该数据的角色;
  • 有专人托管,在需要的时候联系他,由特定方式转发给你,如加密邮件等

分析

  • 对于第二种方式,相对简单粗暴,但是不利于管理。
  • 第一种方案,你需要依托第三方服务,你得绝对信任他,相信他是不会出问题的;再者,你的数据管理也需要有特定的规范,不然你都不知道你存储了什么数据,更不知道有哪些数据。

针对第一种情况,当我们的数据越来多的时候,我们需要将其状态可控起来,其实就是 date as code, 每次对数据的增删改查,我们都可以有追踪和数据保存。

有哪些方案呢?

在这里,我推荐使用 git-crypt, 其特点如下:

  • 加密后上传 git,在 git 上保存的是二进制文件;
  • 分发密钥给可信开发人员,进行解密,维护配置文件;
  • 解密后为明文内容,如需上传,不用再进行加密,工具自动(配合git hook) 会生成最新的二进制文件后上传;
  • c++编写;
  • Mac 可以通过brew 等方式下载;
  • 利用了加密工具gpg进行加密处理。

GPG

https://ruanyifeng.com/blogimg/asset/201307/bg2013071202.png

要了解什么是 GPG,就要先了解 PGP。

1991 年,程序员 Phil Zimmermann 为了避开政府监视,开发了加密软件 PGP。这个软件非常好用,迅速流传开来,成了许多程序员的必备工具。但是,它是商业软件,不能自由使用。所以,自由软件基金会决定,开发一个 PGP 的替代品,取名为 GnuPG。这就是 GPG 的由来。

gpg 可以对密钥的增删改查进行操作,也可以将公钥发送到 pgp 等服务器,让别人搜索到你,具体操作可以参考阮一峰的这片博文 《GPG 入门教程》

git-crypt 操作

安装 gpg 和 git-crypt

1
2
brew install git-crypt
brew install gpg

gpg version

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
gpg --version
gpg (GnuPG) 2.2.19
libgcrypt 1.8.5
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /Users/c4/.gnupg
支持的算法:
公钥: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
密文: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
    CAMELLIA128, CAMELLIA192, CAMELLIA256
散列: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
压缩:  不压缩,ZIP, ZLIB, BZIP2

生成 gpg userId

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
gpg --full-generate-key
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

请选择您要使用的密钥类型:
   (1) RSA 和 RSA (默认)
   (2) DSA 和 Elgamal
   (3) DSA(仅用于签名)
   (4) RSA(仅用于签名)
  (14) Existing key from card
您的选择是?
RSA 密钥的长度应在 1024 位与 4096 位之间。
您想要使用的密钥长度?(2048) 4096
请求的密钥长度是 4096 位
请设定这个密钥的有效期限。
         0 = 密钥永不过期
      <n>  = 密钥在 n 天后过期
      <n>w = 密钥在 n 周后过期
      <n>m = 密钥在 n 月后过期
      <n>y = 密钥在 n 年后过期
密钥的有效期限是?(0)
密钥永远不会过期
这些内容正确吗? (y/N) y

GnuPG 需要构建用户标识以辨认您的密钥。

真实姓名: guzhongren
电子邮件地址: guzhongren@live.cn
注释: guzhongren
您选定了此用户标识:
    “guzhongren (guzhongren) <guzhongren@live.cn>”

更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)? o
我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘
、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数
发生器有更好的机会获得足够的熵。
我们需要生成大量的随机字节。在质数生成期间做些其他操作(敲打键盘
、移动鼠标、读写硬盘之类的)将会是一个不错的主意;这会让随机数
发生器有更好的机会获得足够的熵。
gpg: 密钥 25DD25A47AEF036A 被标记为绝对信任
gpg: 吊销证书已被存储为‘/Users/c4/.gnupg/openpgp-revocs.d/4FA612D2DB4244E7D64A1C1025DD25A47AEF036A.rev’
公钥和私钥已经生成并被签名。

pub   rsa4096 2020-07-11 [SC]
      4FA612D2DB4244E7D64A1C1025DD25A47AEF036A
uid                      guzhongren (guzhongren) <guzhongren@live.cn>
sub   rsa4096 2020-07-11 [E]

获取 UserID

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
gpg --list-secret-keys --keyid-format LONG
gpg: 正在检查信任度数据库
gpg: 绝对信任密钥 8823E362E95562B8 的公钥未找到
gpg: marginals needed: 3  completes needed: 1  trust model: pgp
gpg: 深度:0  有效性:  4  已签名:  0  信任度:0-,0q,0n,0m,0f,4u
gpg: 下次信任度数据库检查将于 2022-01-26 进行
/Users/c4/.gnupg/pubring.kbx
----------------------------
sec   rsa4096/25DD25A47AEF036A 2020-07-11 [SC]
      4FA612D2DB4244E7D64A1C1025DD25A47AEF036A
uid                 [ 绝对 ] guzhongren (guzhongren) <guzhongren@live.cn>
ssb   rsa4096/DCC72940818AB355 2020-07-11 [E]

sec rsa4096/25DD25A47AEF036A 2020-07-11 [SC]25DD25A47AEF036A就是 gpg userId

git-crypt 操作

初始化

进入需要做加密的 git repo 做 git-crypt 初始化操作,并将上面获取到的 gpg userId 添加进去

1
2
git-crypt init
git-crypt add-gpg-user 25DD25A47AEF036A

加密文件过滤器.gitattributes

格式为: * filter=git-crypt diff=git-crypt ;如下,我需要加密secretfile, *.keysecretdir/**, 那么内容如下:

1
2
3
secretfile filter=git-crypt diff=git-crypt
*.key filter=git-crypt diff=git-crypt
secretdir/** filter=git-crypt diff=git-crypt

清理 config 的 git 缓存

1
git rm -r –cached config

添加需要加密的文件和数据

secretdir文件夹下添加 secret.yaml, 并添加如下内容:

1
username:password

上传到 git 仓库

此步不用担心你的secret.yaml文件以明文的形式上传,git-crypt 会在 commit 之前将过滤后的数据加密成二进制,所以不用担心在仓库中存储敏感信息。

1
2
3
git add .
git commit -m ‘git-crypt’
git push

如果你去 git 仓库中浏览 secret.yaml 文件,会是一个二进制文件,如图:

https://i.loli.net/2020/07/12/lXVnNw5EbKCcvhe.png

协作

与他人协作,别人需要知道对应解密的 key

导出密钥

1
git-crypt export-key ~/Desktop/git-crypt.key

得到 git-crypt.key 后,将该密钥分发给可信的团队成员,团队成员将仓库 clone 下来后,使用如下命令解密即可

1
git-crypt unlock /path/to/git-crypt.key

此时,在本地就可以看到加密后的文件内容了。

更新密钥

因为 git-crypt 没有提供删除或者更新密钥的命令,所以参考了一个 issue: https://github.com/AGWA/git-crypt/issues/47#issuecomment-492939759; 步骤如下:

  • Make a backup (with decrypted files): cp -r . /path/to/backup
  • Save a list of files that are encrypted: git crypt status | grep -v ‘not encrypted’ > ../encrypted-files.txt
  • Make git-crypt forget about itself: rm .git-crypt
  • Delete the encrypted files: awk ‘{print $2}’ ../encrypted-files.txt | xargs rm
  • Commit (at this point you get a repo without git-crypt stuff)
  • Add git-crypt from scratch (init and add-gpg-user)
  • Copy the decrypted files from the backup: awk ‘{print $2}’ ../encrypted-files.txt | while read l; do cp /path/to/backup/$l $l; done
  • Commit (at this point you are done, but be sure to verify things are properly encrypted before publishing)

实践结果:在更新完成之后,协作者需要重新 clone 仓库,然后用新的密钥来解密,对密钥管理者来说操作比较麻烦

总结

在敏感数据越来越多的时候,作为开发者,我们更应该将所有的数据都as code, 为以后维护提供方便。git-crypt确实是一个比较好的选择。

但是git-crypt有一个最大的缺点:

  • 只能添加不能删除 gpg userId, 导致更新密钥会比较麻烦,如果要更新密钥,那么就需要做重置

Refs

Disclaimer

本文仅代表个人观点,与 Thoughtworks 公司无任何关系。


https://cdn.staticaly.com/gh/guzhongren/data-hosting@master/20210819/wechat.ae9zxgscqcg.png