svn 命令_svn 使用 gpg-agent 保存密码的分析

SVN 是常用的源代码管理工具,虽然现在 GIT 更加流行,但 SVN 还是拥有不少的用户。而且如果是在公司里面开发,没有分布式和离线的需求的话, SVN 和 GIT 的功能实际差别并不大。但 SVN 缺少类似 github 、 gitlab 等适合 devops 、 CI/CD 等工具环境,逊色不少。

5938946d79488cbd6453212436f91774.png

早期版本的 SVN 是采用明文的方式保存密码,存在安全隐患,因此在最近的版本中,禁用了明文的方式保存密码。如果想方便使用,不想每次执行 SVN 命令都输入密码,可以考虑使用 gpg-agent 来保存密码。

启动 gpg-agent 后台服务

GnuPG 是一个实现了 OpenGPG 标准(RFC 4880)加密管理工具,支持对文件、邮件等进行加密和签名,以及相应的密钥等的管理。gpg-agent 是 GnuPG 里面的一个后台服务程序,负责进行密钥的管理,也支持对密码的简单缓存处理。

646a628b05c1ab2f5fd39937d079fde7.png

要使用 gpg-agent 来管理 SVN 密码,首先要启动 gpg-agent , gpg-agent 是使用 unix socket 来提供服务,为了使客户端能够找到 gpg-agent 监听的 unix socket 的信息,一个方案是让 gpg-agent 将监听信息写入文件中。另外,也可以设置缓存的时间等参数。

gpg-agent的常用参数有:

  • --daemon :以后台服务的方式运行
  • --write-env-file :将监听信息写入文件中,默认为 ${HOME}/.gpg-agent-info
  • --default-cache-ttl :设置缓存的密码的默认生命周期,默认是 600 秒(10分钟),在这段时间内如果未再次访问,则会删除密码
  • --max-cache-ttl :设置缓存的密码的最大生命周期,默认是 7200 秒(2小时),密码加入缓存后超过这个时间,即使频繁使用也会删除。
  • --allow-preset-passphrase :支持应用程序设置密码,如果没有这个选项,则不能应用程序主动设置密码,而是只能应用程序向 gpg-agent 请求密码,然后 gpg-agent 再向用户请求密码。

一个启动 gpg-agent 命令的例子为:

[smlc@test code]$ gpg-agent --daemon --write-env-file ${HOME}/.gpg-agent-info --allow-preset-passphraseGPG_AGENT_INFO=/home/smlc/.gnupg/S.gpg-agent:4614:1; export GPG_AGENT_INFO;[smlc@test code]$

后续其他应用程序在使用 gpg-agent 服务前,需要先设置 GPG_AGENT_INFO 环境变量,例如:

[smlc@test code]$ GPG_AGENT_INFO=/home/smlc/.gnupg/S.gpg-agent:4614:1[smlc@test code]$ export GPG_AGENT_INFO

或者简单一些,直接执行下面的命令(bash):

[smlc@test code]$  source  ${HOME}/.gpg-agent-info

如果是在自己编写的应用程序内部使用gnupg功能,一般也是应该读取 GPG_AGENT_INFO 环境变量,然后根据此环境变量的值,冒号分隔的第一段,一个 unix socket 文件名,打开这个 unix socket ,发送相应的命令。

SVN 使用 gpg-agent 存储密码

当使用上述方式启动了 gpg-agent 后台服务,并且对当前shell设置了 GPG_AGENT_INFO 环境变量,后续执行 svn 命令时,如果 gpg-agent 未保存密码,则会提示用户输入密码,然后此密码会被 gpg-agent 保存起来,后续再执行 svn 命令时,只要密码未过期,就可以直接使用,无需再次输入密码。

在某些场景下,如果需要通过应用程序来预先设置好密码,供后续 svn 命令使用,那么可以通过 gpg-connect-agent 命令来完成。(重复一下,启动 gpg-agent 时,需要加上 --allow-preset-passphrase 参数)。

gpg-connect-agent管理密码缓存的常用命令为:

  • PRESET_PASSPHRASE :设置密码,其中 cache_id 是密码的名称用来唯一标识,timeout 是超时时间,目前只允许 -1 表示无限长(永不超时),hexstring 是 16 进制表示的密码字符串(相当于base16编码)
  • GET_PASSPHRASE [--data] [--no-ask] :获取密码,--data表示获取的密码单独一行输出,--no-ask表示当gpg-agent没有换出指定cache_id的密码时,不询问用户输入密码,而是直接返回错误。cache_id 是密码名称用来唯一标识,error_message、prompt、description是询问用户输入密码时的相关信息。
  • CLEAR_PASSPHRASE :清除密码,删除密码名称为 cache_id 的指定密码

svn 在存储密码到 gpg-agent 时,使用 SVN 服务器的 realmstring 的 md5 值作为 cache_id (假设值为 c3fcd3d76192e4007dfb496cca67e13b ),如果密码为 abc (base16编码为:616263),那么设置缓存的命令为:

[smlc@test code]$ gpg-connect-agent 'PRESET_PASSPHRASE c3fcd3d76192e4007dfb496cca67e13b -1 616263' /byeOK[smlc@test code]$ 

设置后,获取缓存的密码值的命令的执行结果为:

[smlc@test code]$ gpg-connect-agent 'GET_PASSPHRASE --data --no-ask c3fcd3d76192e4007dfb496cca67e13b nop nop nop'  /byeD abcOK[smlc@test code]$