在命令行中安全存取密钥,避免在CLI中出现明文密钥

使用 pass 在 Linux CLI 中安全地使用和保存 Key,避免在命令行或配置文件中包含明文密钥

pass (全称为 password-store)是 Linux 上的一个简单的命令行密码管理器。它将密码存储在一个 GPG 加密后的文件里。这些加密后的文件很好地组织按目录结构存放。

因为 pass 使用 GPG 密钥对来加密存储的信息。为此,需要首先生成一个 GPG 密钥。如果已经有GPG密钥的可以直接跳过下面GPG这个一级段落。

GPG

生成GPG密钥对

生成一个GPG密钥对

gpg --full-generate-key

接下来按照提示进行生成即可。

列出拥有的公钥和私钥

列出拥有公钥和私钥的 GPG 密钥的长格式

gpg --list-secret-keys --keyid-format=long

从 GPG 密钥列表中复制您想要使用的 GPG 密钥 ID 的长格式。用Github文档中的例子,GPG 密钥 ID 为 3AA5C34371567BD2

$ gpg --list-secret-keys --keyid-format=long
/Users/hubot/.gnupg/secring.gpg
------------------------------------
sec   4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]
uid                          Hubot <hubot@example.com>
ssb   4096R/4BB6D45482678BE3 2016-03-10

3AA5C34371567BD2是主密钥 (master key / secret key) 的ID。而4BB6D45482678BE3是与该主密钥相关联的子密钥 (secret subkey) 的ID。

最后长度为16的”3AA5C34371567BD2”称为Long Key ID,最后长度为8的”71567BD2”称为Short Key ID

主密钥和子密钥是与GPG主密钥对关联的密钥对。主密钥通常用于证明密钥的所有权和身份,而子密钥则用于加密和签名数据。

主密钥与子密钥共享相同的公钥,但拥有不同的私钥。

撤销证书

建议在生成GPG密钥后就立刻生成并安全保存好撤销证书,一旦丢失密钥或密钥被盗用,你就可以立刻发布撤销证书以防止密钥被滥用。

生成撤销主密钥的撤销证书:

gpg --output revoke.asc --gen-revoke 3AA5C34371567BD2

gpg --output revoke.asc --gen-revoke hubot@example.com

生成撤销子密钥的撤销证书:

gpg --output revoke_subkey.asc --gen-revoke 4BB6D45482678BE3

在生成GPG密钥的撤销证书时,你的当前证书并不会立刻失效。只有当你发布或使用这个撤销证书后,你的密钥才会被标记为已撤销。

通常情况下,只需要生成并保存主密钥的撤销证书。这是因为当你使用主密钥的撤销证书时,它会撤销整个密钥对,包括主密钥和所有相关的子密钥。通常,我们只在主密钥丢失或被盗用时才需要使用主密钥的撤销证书。

在你只想撤销某一个特定的子密钥,而并不想撤销主密钥和其他子密钥时才需要生成和使用子密钥的撤销证书。例如,如果你认为某个子密钥可能已经不安全(如可能已经被窃取),但你的主密钥和其他子密钥仍然安全,那么就可以只撤销那个不安全的子密钥。

导出

导出公钥并将其保存到文件中:

gpg --export -a "hubot@example.com" > hubot-pub.asc

"hubot@example.com"命令参数将只导出指定用户名的密钥。(主密钥和子密钥都可以这样导出。建议用这种方式来备份密钥。

也可以替换成GPG密钥ID 如 3AA5C34371567BD2 。这样只会导出主密钥不会导出子密钥 (gpg --export -a 3AA5C34371567BD2)

-a是可选项全称为--armor 选项将导出的公钥转换为ASCII格式。这使得公钥可以方便地在电子邮件、社交媒体等文本消息中共享。

导出全部私钥并将其保存到文件中:

gpg --export-secret-keys "hubot@example.com" > hubot-privkey.asc

单独导出主密钥的私钥(不常用)使用 --export-secret-key 单独导出子密钥的私钥(不常用)使用 --export-secret-subkeys

导入

导入公钥:

gpg --import hubot-pub.asc

导入私钥:

gpg --import hubot-privkey.asc

在导入私钥时,会要求你输入当初设定的保护该私钥的密码,必须正确输入才能成功导入。

保存

安装pass

sudo apt-get install pass

初始化存储库

可以使用 email-id 或 gpg-id 进行初始化 pass 的存储库。

以上面Github示例gpg信息为例:

pass init hubot@example.com

存储密钥

通过如下命令存储密钥:

pass insert openai/key
pass insert fossa/api

根据提示输入两次密钥并回车确认。

pass 实际上将凭据加密后存储在 ~/.password-store 路径。而上面的 openai/api 指的就是凭据在该目录中的存储路径。

~/.password-store$ tree
.
├── fossa
│   └── api.gpg
└── openai
    └── key.gpg

你可以通过运行 pass / pass ls / pass show命令来确认添加完成,输出应该类似于:

Password Store
├── fossa
│   └── api
└── openai
    └── key

编辑现有密码

pass edit openai/key

移除密码

pass rm openai/key

使用

此后就可以运行

pass openai/key

将 API 密钥内容输出到终端。每次获取密钥内容时都需要输入GPG密码来解锁。

在CLI中使用

$(pass openai/key)

来代替对密钥的明文引用。

之后但凡需要用到 OpenAI API 密钥的地方,都可以换成包含上述命令的subshell。

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $(pass openai/key)"

如果要为终端添加环境变量 OPENAI_API_KEY,只用在 .bashrc(或你所用其他终端的配置文件)中加入:

export OPENAI_API_KEY=$(pass openai/key)

export关键字用于设置环境变量。环境变量是在Shell会话中可用的全局变量,其他程序可以读取和使用这些变量。

这样就可以简化成

curl https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY"

这就避免了在配置文件中包含明文密钥。

类似地,在运行 Docker 等需要传递 API 密钥作为环境变量的场合,也可以用上述 subshell 代替密钥明文,例如

docker run \
    -e FOSSA_API=$(pass fossa/api) \
    [OPTIONS ...] \
    IMAGE

使用Git

使用Git来同步加密后的密码,让我们管理密码更方便。

pass git init

然后就可以指定跟踪的远程仓库了

pass git remote add <name> <url>

可以把~/.password-store这个密码仓库当成普通仓库来用。使用 pass git git-command-args 唯一的不同点在于每次我们新增或修改一个密码,pass都会自动将该文件加入索引并创建一个提交。

Pass还有很多功能,包括生成密码、添加密码的备注信息等等。

此外还有 QTPass 这样的图形界面,不过最初的目的本身就是为了在命令行中避免暴露明文密钥,所以在这个需求下的图形化界面并没有太大的用处。

Windows平台下也存在微软官方开发的 PowerShell 模块 SecretManagement ,不过我在Win平台下这样的需求不是很高就没有尝试。macOS原生也带有钥匙串访问功能。此外,还可以尝试1Password CLI这样的软件来实现同样的功能。

参考链接:

pass官网 https://www.passwordstore.org/

https://git.zx2c4.com/password-store/about/

pass:一款简单的基于 Linux 命令行的密码管理工具 https://linux.cn/article-8650-1.html

GPG https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification

如何在命令行中安全存取密钥信息 https://sspai.com/prime/story/terminal-credentials-tips

PowerShell SecretManagement Module https://woshub.com/powershell-secretmanagement-module/