如何在命令行中安全存取密钥信息:以 OpenAI API 密钥为例
2023-5-18 17:56:28 Author: sspai.com(查看原文) 阅读量:32 收藏

大量涌现的 AI 项目引发了如何有效管理和取用 API 密钥的问题。每次复制粘贴过于麻烦,明文写进配置文件也不安全。但通过合理利用内置功能或第三方工具,就能用加密存储代替明文密钥,达到兼顾安全和便捷的目的。

AI 的持续火热带动了很多人尝鲜的兴趣。而要使用目前大量涌现的 AI 项目,一个非常普遍的前提条件就是填入自己的 API 密钥,从而调用 OpenAI 等商业服务提供的模型。

这就产生了如何有效管理和取用 API 密钥的问题。由于密钥都是随机而冗长的,当然不可能像密码那样凭记忆输入。网页端工具倒是可以用浏览器或第三方软件的密码管理功能填写;但很多 AI 工具都需要在命令行下运行。例如,OpenAI 的官方命令行工具、以及很多调用 GPT 的 Docker 项目,都要求将 OpenAI API 密钥作为环境变量才能运行。

对此,如果每次都临时复制粘贴,不仅非常麻烦,还会在终端历史记录中留下明文密钥内容,不符合安全原则。

OpenAI 的一篇帮助文档谈及了这个问题,指出可以将密钥内容存储在终端配置文件(例如 .zshrc)中;类似地,Docker 也支持通过 .env 等外部文件传入环境变量。但这只能解决问题的一半,仍然会导致密钥内容的明文存储。这种问题做法导致的安全隐患,正是 GitHub 提供仓库密文扫描功能的背景。

实际上,通过合理利用内置功能或借助第三方工具,就能用加密存储代替明文密钥,达到兼顾安全和便捷的目的。下面,我们就以存储和调用 OpenAI API 密钥为例,说明不同平台上的解决方案。当然,这些方法也适用于在命令行环境中存取任何登录密码或其他凭据信息。

macOS

如果你是苹果「全家桶」用户,习惯用系统自带的密码管理功能,大概知道可以通过内置的「钥匙串访问」(Keychain Access,位于 /Applications/Utilities 目录下)查看和管理密码。

所谓「钥匙串」,是指 macOS 用来加密存储凭据信息的容器,除了网站密码,还包括已登录 WiFi 的密码、第三方证书等。

但较少有人知道的是,并不是只有 Safari 浏览器或适配了钥匙串的第三方应用可以写入钥匙串,用户自己也可以手动添加任何想要加密保存的信息。

例如,如果要用钥匙串存储 OpenAI 的 API 密钥,可以在「钥匙串访问」app 中选择「文件」>「新建安全备注项」,在「名称」中填写 OPENAI_API_KEY,在「备注」中填写密钥内容。(之所以选择「安全备注」类型而不是「登录项」,是因为 API 密钥是一个可独立使用的凭据,不需要同时保存用户名。)

当然,添加和访问钥匙串也不是一定要通过「钥匙串访问」app,还可以完全在命令行中完成。相关的命令是 security(1),用其添加密码的一般语法是:

security add-generic-password [-s service] [-a account] [-D kind] [-w password]

其中,-s-a-w 三个必填项分别用来指定服务名称、用户名和密码。-D 是可选的,指该钥匙串项目的类型。

例如,如果想添加一条存储 OpenAI API 密钥的安全备注,可以运行:

security add-generic-password -D "secure note" -s "OPENAI_API_KEY" -a "OPENAI_API_KEY" -w

这里,我们用 -D 选项指定类型为 secure note,即安全备注(填写用户名对于安全备注其实是多余的,只是因为 security 不够灵活的语法要求才不得不填一个)。

此外,注意到命令中没有直接包含 API 密钥内容,最后直接以一个空的 -w 选项结尾了。这样运行的效果是弹出一行类似登录账户时的提示,要求当场输入密钥内容。这就避免了密钥明文出现在命令执行历史里,更加安全。

此后,但凡需要调用保存的密钥,运行:

security find-generic-password -s "OPENAI_API_KEY" -w

就会返回密钥的原文。

你可能会疑问为什么这个操作不需要任何授权。其实,根据钥匙串的规则,访问其内容一般确实需要密码,但一个程序访问它自己添加的内容除外。我们之前就是通过 security 命令添加的钥匙串,因此再用 security 命令来搜索和获取其内容,可以免输密码。

进一步延伸,但凡需要用到 OpenAI API 密钥的地方,都可以换成包含上述命令的subshell,即 $(security find-generic-password -s "OPENAI_API_KEY" -w)

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

export OPENAI_API_KEY=$(security find-generic-password -s "OPENAI_API_KEY" -w)

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

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

docker run \
    -e OPENAI_API_KEY=$(security find-generic-password -s "OPENAI_API_KEY" -w) \
    [OPTIONS ...] \
    IMAGE

就会将密钥内容作为 OPENAI_API_KEY 变量传给将要运行的 IMAGE

Linux

与 macOS 不同,常见的 Linux 发行版没有统一的内置凭据管理工具,但绝大多数发行版的官方软件源都收录了 pass(全称为 password-store)这款命令行工具。这也是被广泛推荐、符合 UNIX 简洁风格的解决方案。因此,本文也选择它作为 Linux 下的推荐方案来演示。


文章来源: https://sspai.com/prime/story/terminal-credentials-tips
如有侵权请联系:admin#unsafe.sh