Jul 20
我们知道 Gnu PG 是非常重要的加密工具,它可以帮助我们加密数据或者对使用的文件、文本进行签名以确保数据的真实性。Gnu PG 被广泛的应用于电子邮件传递、软件包打包等过程中。下面我们就来谈谈 Gnu PG 在 GIT 中的使用。
 
1、标签、提交等的签名
通常提交源码时,我们直接采用
$ git commit -m 'something added.'
对于这种提交方式,我们无法确认是否本人做了这些修改。为了防止这种情况发生,我们可以尝试
$ git commit -S <gpg-key-id> -m 'something added.' 
其中 <gpg-key-id> 就是用户的Gnu PG 的密匙ID。该命令执行时会提示用户输入该 <gpg-key-id> 的口令,随后对这次提交做了 GPG 签名,如此一来便可确信是本人做了这次递交。类似地情况也可运用到标签上来,例如
$ git tag v1.0 -s -u <gpg-key-id> -m 'tagged with important information.'
如果觉得每次手动指定 Gnu PG 密匙 ID 比较麻烦,可以通过下述方式自动指定
$ git config --global user.signingkey <gpg-key-id>
 
2、push/pull的口令缓存
我们在将版本库的修改同步到远程版本库时,通常需要输入账户与口令。如果版本库中有多次提交需要同步,那么账户、口令就需要输入多次。早期 GIT 版本库同步时,由于没有提供密码的缓存机制,为了免去重复输入账户名与口令,通常直接将密码明文的保存在.git/config文件之中。例如,
$ git remote add origin https://<username>:<password>@github.com/someone/repo
其中 <username> 与 <password> 就是账户与密码。很明显,以明文方式存储隐私信息是非常不可取的。因此新版的 GIT 中提供了新的办法,大体来说有两种:一、利用 git-credential;二、利用 ~/.netrc 或者 ~/.authinfo 等文件实现自动读取隐私信息。
 
credential 机制有点类似于 Gnu PG 代理,它能够缓存用户的密码,例如
$ git config --global credential.helper 'cache --timeout=3600'
如此设置之后,当我们输入完账户密码之后,GIT 就会缓存密码1个小时。实际上,credential 的机制还有好几个,有兴趣的朋友请自行阅读文档
$ man git-credential
 
另一方面,GIT 利用 ~/.netrc 等文件存取账户名与密码的方式与 ftp 的工作方式类似。例如,
$ cat ~/.netrc
machine github.com
  multilinetoken <hashnumber>
  login <username> password <password>
随后,我们便可以执行
$ git push origin master
此时 GIT 会自动读取 ~/.netrc 中账户信息将本地版本库修改同步远程端 GIT 服务器。这样一来,隐私信息的安全完全有赖于 ~/.netrc 文件权限了,通常,会对该文件的权限作如下设置
$ chmod 600 ~/.netrc
 
不过即使是这样,我们可能还是觉得安全性不够。例如用户登录电脑后有事需要离开一段时间,但没有及时开启密码屏保,这就难保 ~/.netrc 的信息不被泄漏。下面就来谈谈进一步的保密措施,那就是用 Gnu PG 加密 ~/.netrc 文件
$ gpg -o ~/.netrc.gpg -er <gpg-key-id> ~/.netrc
随后再对 GIT 做如下配置
$ git config --global credential.helper 'netrc -f ~/.netrc.gpg -d'
为了让 GIT 支持如上的修改,还需要开启 git-credential-netrc。在 Fedora 19 中,该文件位于 /usr/share/doc/git-<version>/contrib/credential/netrc 目录之中。需要将它置于 /usr/libexec/git-core 目录之下,并增加可执行权限
$ sudo cp /usr/share/doc/git-<version>/contrib/credential/netrc/git-credential-netrc /usr/libexec/git-core
$ sudo chmod +x /usr/libexec/git-core/git-credential-netrc
当然,用户也可以试试我的 Fedora 源中重新打包的 GIT。好了,现在再试试远程版本库的同步吧。
 
用 Gnu PG 加密 ~/.netrc 有个问题需要指出,那就是原先 ~/.netrc 的功能并不能被完全拓展到 ~/.netrc.gpg。换而言之,当我们执行 ftp 命令时,~/.netrc.gpg 并不能被解析。因此,我们需要适当分离 ~/.netrc 中内容以确保各个程序能够合理的工作。
 
3、版本库中文件的自动加密/解密
 
通常版本库中不太可能有什么隐私信息,不过随着很多人将 Linux 配置文件制成 GIT 版本库,隐私问题也就随之而来了。有些配置文件,例如 SSH 的私匙文件,再如 Emacs 的 GNUS 与 ERC 等,它们的密码有一部分只能以明文的方式保存的。如果将它们的配置发布到公开的 GIT 版本库中显然不是很合适。那么有没有办法将这些隐私文件以加密的形式保存到远程版本库,但本地工作目录中则仍以解密形式存在呢?答案仍是使用 GPG,主要是利用 GIT 的 filter 机制来配合 GPG 的使用。具体来说是这样的:
$ git config --local filter."gpg".smudge 'gpg -d --batch --no-tty -r <gpg-key-id>'
$ git config --local filter."gpg".clean 'clean = gpg -ea -q --batch --no-tty -r <gpg-key-id>'
$ git config --local diff."gpg".textconv decrypt
接着将需要将解密的文件名列表加入.gitattributes或者.git/info/attributes,例如
/path/to/id_rsa filter=gpg diff=gpg
/path/to/gnus.el filter=gpg diff=gpg
现在你可以尝试将id_rsa、gnus.el加入版本库了,当它们被加入到版本库时,GIT会利用 clean 所指定的方式进行加密。而当它被检出时,GIT 会调用 smudge 进行解密。需要注意的是,整个过程需要预先运行 gpg-agent。
 
用 GIT 管理配置文件的过程中,可能还会碰到一个特殊的文件需要加密,那就是 GIT 本身的配置文件。这个需求仍然与登录密码相关,最直接的例子就是 Github 的 token。很明显,直接加密整个 ~/.gitconfig 文件并不是很好的选择。这里提供一种方法,可以将需要加密的那部分配置分离出来。具体来说就是在 GIT 的配置文件中增加include部分,例如
$ git config --global include.path '~/.gitrepo'
并在 ~/.gitrepo 中加入与隐私相关的部分:
$ nano -w ~/.gitrepo
[github]
      username = <username>
      token = <hashnumber>
至于如何将 ~/.gitconfig、~/.gitrepo 纳入我们的配置文件版本库,这里就不多说。最后就是加密~/.gitrepo文件,这个非常简单。例如,~/.gitrepo 在版本库中的名字gitrepo,下面只需要再在.gitattributes中增加一行
/path/to/gitrepo filter=gpg diff=gpg

 

以上就是关于 GPG 与 GIT 的一些应用,希望对大家有用。
Jun 13

有时使用某个应用程序的时候,你需要非常频繁地使用你的 Gnu PG 密钥,这就意味着你需要多次输入密匙解密口令。相当多的应用程序支持将口令(密码)缓存起来方便用户使用。但是出于安全的目的,却不能让缓存的口令(密码)在多个程序之间交叉使用。不过,Gnu PG 提供了很安全的密码缓存方式,也即 Gnu PG 的代理 gpg-agent。通过它,多个应用程序可以共用 Gnu PG 密匙的解密口令。如果你在使用某个应用程序的时候输入了密匙解密口令,其他应用程序可以在一段时间内不用再请求输入口令也能解密 Gnu PG 密钥。下面就来谈谈如何设置 Gnu PG 的代理。

尽管我们不谈论 Gnu PG 公匙、密匙的生成与使用过程,但是使用 Gnu PG,第一步当然是安装它:
$ sudo yum install gnupg
通常,Gnu PG 程序本身就有代理功能。不过在图形界面下,Gnu PG 的代理功能需要用 pinentry 来开启,所以需要先在 Linux 中安装 pinentry 程序。
$ sudo yum install pinentry-gtk 
现在创建 gpg-agent 的配置文件:
$ cat > ~/.gnupg/gpg-agent.conf << EOF 

# PIN entry Program
#pinentry-program /usr/bin/pinentry-curses
#pinentry-program /usr/bin/pinentry-qt4
#pinentry-program /usr/bin/pinentry-kwallet
pinentry-program /usr/bin/pinentry-gtk-2
# Keyboard control
no-grab
# Cache timeout: 3 hours
default-cache-ttl 10800
#default-cache-ttl-ssh 10800

EOF
这个配置指明了 pinentry 程序、口令缓存的超时时间等等。接着激活 Gnu PG 的代理能力,这只要使用下面这一行即可
$ echo "gpg-agent" >> ~/.gnupg/gpg.conf
这一行告诉 Gnu PG 在需要密码时使用 gpg-agent,但前提是需要 gpg-agent 事先已经工作。运行 gpg-agent 的方法很简单:
$ eval $(gpg-agent --daemon)
停止 gpg-agent 的方法是:
$ pkill -u "$USER" gpg-agent
 
为了让 gpg-agent 的使用更加方便,我们自然希望它能够随机器启动而自动工作,这可通过在 /etc/profile.d/ 中作如下的配置来实现
$ sudo cat > /etc/profile.d/gpg-agent.sh << EOF

#!/bin/sh

envfile="${HOME}/.gnupg/gpg-agent.env"
if test -f "$envfile" && kill -0 $(grep GPG_AGENT_INFO “$envfile" |cut -d: -f 2) 2>/dev/null; then
     eval "$(cat :$envfile")"
else
     eval "$(gpg-agent --daemon --write-env-file "$envfile")"
fi
export GPG_AGENT_INFO # the env file does not contain the export statement

EOF

$ sudo chmod 755 /etc/profile.d/gpg-agent.sh
以上的设置使得每位登录 Linux 的用户自动启用 gpg-agent。一般而言,一个会话只允许开启一个 gpg-agent 进程。关于这一点,我们可以从上面的配置中可以看到。如果我们只希望为某个用户启用 gpg-agent,可在 ~/.xprofile、~/.xsession 或者 ~/.xinitrc 中添加下面这一行,这取决于我们使用的图形界面的启动方式,例如:
$ echo 'eval "$(gpg-agent --daemon)"' >> ~/.xprofile
如果用户不使用图形界面的话,也可以将上面这一行写入 ~/.bash_profile。通过前面这些设置便能自动启动 gpg-agent 了。关于 gpg-agent 的更多设置,请自行参看 gpg-agent 的手册页
$ man gpg-agent
 
实际上,从手册页中可以看到,gpg-agent 还可以作为 ssh-agent,这只需要在命令行 gpg-agent 中增加 --enable-ssh-support 选项即可。下面给出一个自动作为 ssh-agent 与 gpg-agent 的配置:
$ cat >> ~/.bash_profile << EOF

#!/bin/sh

# Start the GnuPG agent and enable OpenSSH agent emulation
gnupginf="${HOME}/.gpg-agent-info"

if pgrep -u "${USER}" gpg-agent >/dev/null 2>&1; then
    eval `cat $gnupginf`
    eval `cut -d= -f1 $gnupginf | xargs echo export`
else
    eval `gpg-agent -s --enable-ssh-support --daemon`
fi 

EOF
 
值得指出的是,Gnome 桌面自身提供的 Gnome-keyring 也整合了 gpg-agent 功能,这取决于 Gnome-keyring 包编译过程有没有开启 gpg-agent 选项。如果我们想禁用 Gnome-keyring 的 gpg-agent 功能,除去修改源码的编译选项之外,还可作如下操作来实现
$ cp /etc/xdg/autostart/gnome-keyring-gpg.desktop ~/.config/autostart/gnome-keyring-gpg.desktop
$ echo "X-GNOME-Autostart-enabled=false" >> ~/.config/autostart/gnome-keyring-gpg.desktop
实际上,上面的操作与如下的半图形化操作相同:
$ gnome-session-properties
在随后出现的图形框中勾选掉 gnome-keyring-gpg 功能。如果只是想临时禁用 Gnome-keyring,可执行
$ sudo pkill gnome-keyring