CentOS 下使用 pass 与 GPG 加密安全存储 Docker 登录凭证 📅 2026/7/8 4:23:19 1. 项目概述在容器化部署和持续集成的日常工作中Docker 登录凭证比如访问 Docker Hub 或私有镜像仓库的用户名和密码的管理是一个既基础又容易被忽视的安全环节。很多开发者包括我自己在早期都习惯性地在~/.docker/config.json文件里看到一串 base64 编码的密码就以为万事大吉了。实际上这种明文存储尽管是编码的方式无异于把钥匙藏在门垫下面——稍微懂点技术的人就能轻松拿到。尤其是在 CentOS 这类常用于生产环境的服务器上一旦服务器被入侵这些凭证就成了攻击者进一步渗透的跳板。今天我就来分享一个在 CentOS 上利用passPassword Store这个遵循 Unix 哲学的命令行密码管理器来安全存储 Docker 登录凭证的实战方案。这不仅仅是换个地方存密码而是建立一套基于 GPG 加密、与 Git 集成、且被 Docker 原生支持的凭证管理体系彻底告别密码“裸奔”的时代。2. 为什么选择 pass 作为 Docker 的凭证助手在深入实操之前我们有必要厘清为什么是pass而不是其他方案。Docker 支持多种凭证存储后端比如 macOS 的osxkeychain、Windows 的wincred以及在 Linux 上默认会尝试寻找的pass和secretservice。2.1 核心优势分析首先pass的本质是一个基于 GnuPGGPG加密的文本文件管理器。它的工作原理非常简洁优雅基于目录和文件你的所有密码都被组织成目录树结构每个密码是一个独立的 GPG 加密文件。例如Docker/registry.hub.docker.com这个路径对应一个加密文件里面存放着 Docker Hub 的密码。GPG 非对称加密这是安全的核心。你用一个 GPG 公钥加密密码文件只有持有对应私钥的人或进程才能解密。这意味着即使整个密码存储目录被拷贝走没有你的私钥也无法读取内容。与 Git 无缝集成pass可以初始化一个 Git 仓库来管理密码文件的版本历史。这对于团队协作、密码变更追踪和异地备份极其有用。命令行友好完全通过命令行操作非常适合服务器环境和自动化脚本。对于 Docker 而言它需要的只是一个实现了特定协议store,get,erase的助手程序。docker-credential-pass就是这个协议的实现者它作为pass和 Docker 引擎之间的桥梁。2.2 与其他方案的对比直接存储在config.json默认行为如前所述base64 编码不是加密等同于明文存储。这是最不安全的方式应坚决避免。secretservice(如 GNOME Keyring, KWallet)这是一个桌面环境下的守护进程服务。在生产服务器上通常没有图形界面运行和维护这些服务会增加复杂性。而且在纯命令行环境下调用有时会遇到 DBus 通信问题。第三方商业密码管理器插件Docker 也支持像1password这样的插件但这通常需要额外的订阅、复杂的配置并且可能不适合内网隔离环境。因此pass方案在 Linux 服务器上展现出了独特的优势轻量、安全、无外部依赖仅需 GPG、易于自动化、且被 Docker 官方列为默认的 Linux 凭证存储后端。3. 在 CentOS 7/8 上部署 pass 与 Docker 凭证助手下面我们进入实战环节。我将以 CentOS 7 为例步骤同样适用于 CentOS 8 或 Rocky Linux、AlmaLinux 等衍生系统。3.1 系统环境准备与依赖安装首先确保你的系统是最新的并安装必要的工具链。# 更新系统包 sudo yum update -y # 安装 EPEL 仓库Extra Packages for Enterprise Linux提供更多软件包 sudo yum install -y epel-release # 安装核心依赖GnuPG用于加密、Git用于密码库版本管理、以及编译工具 sudo yum install -y gnupg2 git make gcc gcc-c # 确认 GPG 版本 gpg --version | head -n1注意CentOS 8 及之后版本可能使用dnf包管理器将上述命令中的yum替换为dnf即可。如果系统已经安装了较新版本的 GPG如gpg而非gpg2后续命令可能需要相应调整。3.2 生成与备份 GPG 密钥对这是整个体系的安全基石。如果你还没有 GPG 密钥需要生成一对。# 生成一个新的 GPG 密钥对。以下命令会进入交互式提示。 gpg --full-generate-key在交互过程中我建议如下选择密钥类型RSA and RSA(默认)。密钥长度4096更高的安全性。有效期根据安全策略选择例如1y一年或0永不过期。生产环境建议设置有效期。输入你的姓名和邮箱这将成为密钥的标识。设置一个强密码短语Passphrase来保护你的私钥。这个密码非常重要务必牢记。生成完成后列出你的密钥以确认gpg --list-secret-keys --keyid-format LONG输出类似sec rsa4096/3AA5C34371567BD2 2023-10-27 [SC] [expires: 2024-10-26] Key fingerprint 1234 5678 9ABC DEF0 1234 5678 9ABC DEF0 1234 uid [ultimate] Your Name your.emailexample.com ssb rsa4096/42B317FD4BA7E9E7 2023-10-27 [E] [expires: 2024-10-26]记下rsa4096/后面的密钥 ID这里是3AA5C34371567BD2。我们后续会用到。实操心得务必立即备份你的私钥和公钥私钥丢失意味着所有用该公钥加密的密码都无法解密。# 导出私钥谨慎保管 gpg --export-secret-keys --armor YOUR_KEY_ID private-key-backup.asc # 导出公钥 gpg --export --armor YOUR_KEY_ID public-key-backup.asc将private-key-backup.asc文件离线存储在绝对安全的地方如加密的U盘。3.3 安装与初始化 pass接下来安装pass本身。# 从 EPEL 仓库安装 pass sudo yum install -y pass # 初始化 pass 存储库使用上一步生成的 GPG 密钥 ID pass init YOUR_KEY_ID # 例如pass init 3AA5C34371567BD2这个命令会在~/.password-store/目录下创建一个新的密码存储库并使用你的公钥进行初始化。你可以测试一下# 插入一个测试密码 pass insert Test/MyFirstPassword # 它会提示你输入两次密码内容例如输入SuperSecret123! # 查看密码列表 pass ls # 应该显示 Test/MyFirstPassword # 获取并显示密码会要求输入 GPG 私钥的密码短语 pass Test/MyFirstPassword3.4 编译安装 docker-credential-passCentOS 的默认仓库里通常没有docker-credential-pass这个二进制文件我们需要从源码编译。它的源码在 Docker 的docker-credential-helpers项目中。# 1. 安装 Go 语言环境编译所需 sudo yum install -y golang # 2. 下载 docker-credential-helpers 源码 git clone https://github.com/docker/docker-credential-helpers.git cd docker-credential-helpers # 3. 编译 pass 版本的 helper make pass # 或者指定编译go build -o docker-credential-pass ./pass/cmd # 4. 将编译好的二进制文件移动到系统 PATH 目录 sudo cp ./bin/docker-credential-pass /usr/local/bin/ # 5. 验证是否安装成功 docker-credential-pass version # 应该输出类似 docker-credential-pass (github.com/docker/docker-credential-helpers) v0.8.0 的信息3.5 配置 Docker 使用 pass 作为凭证存储现在我们需要告诉 Docker 使用我们刚刚安装的docker-credential-pass。编辑 Docker 客户端配置文件~/.docker/config.json。如果文件不存在就创建它。vim ~/.docker/config.json输入以下内容{ credsStore: pass }保存并退出。这个配置告诉 Docker 引擎默认使用pass作为所有仓库的凭证存储后端。重要提示如果你之前已经用docker login登录过~/.docker/config.json里可能会有旧的、base64 编码的auths字段。务必先执行docker logout退出所有仓库再添加credsStore: pass配置否则 Docker 可能仍会读取旧的不安全凭证。4. 实战使用 pass 管理 Docker 登录流程配置完成后我们来体验一下全新的、安全的登录流程。4.1 登录 Docker Hub现在当你运行docker login时Docker 会调用docker-credential-pass。docker login你会看到和以前类似的交互提示可能会是 Web 登录流程或用户名密码提示。成功登录后神奇的事情发生了你的凭证不会以明文形式出现在~/.docker/config.json里。取而代之的是pass存储库中多了一个条目。检查一下pass ls # 你应该会看到一个类似于 docker-credential-helpers/docker-pass-initialized-check 的条目这是 helper 的初始化标记 # 以及一个真正的凭证条目例如 # DockerHub/docker.io # 或者根据你登录的仓库地址 pass ls DockerHub/ # 查看具体内容 pass DockerHub/docker.io你会发现pass里存储的是一个 JSON 结构包含了服务器地址、用户名和密码或令牌。这一切都是被你的 GPG 公钥加密的。4.2 登录私有镜像仓库登录私有仓库的流程完全一样只需指定仓库地址。docker login registry.mycompany.com:5000输入用户名和密码后凭证会被安全地存储。在pass中路径可能会是Docker/registry.mycompany.com:5000。4.3 自动化与非交互式登录在 CI/CD 流水线中我们通常需要非交互式登录。pass方案同样胜任。方法一使用--password-stdin(推荐)这是 Docker 官方推荐的方式可以避免密码出现在命令行历史或进程列表中。# 假设你的密码已经保存在一个环境变量或保密的 CI 变量中 echo $MY_DOCKER_PASSWORD | docker login -u myusername --password-stdinDocker 会从标准输入读取密码并通过docker-credential-pass安全地存储起来。后续的docker pull或docker push操作Docker 会自动从pass中获取解密后的密码。方法二预先使用pass insert插入密码你也可以提前将密码存入pass这样docker login时甚至无需交互。# 首先手动或通过脚本将密码存入 pass需要输入一次 GPG 密码短语 pass insert -m DockerHub/docker.io # 然后粘贴你的 JSON格式为 # { # ServerURL: https://index.docker.io/v1, # Username: myusername, # Secret: my_password_or_token # } # 按 CtrlD 结束输入。 # 之后docker login 可能会更顺畅或者在某些配置下直接可用。 # 更常见的做法是配置好 credsStore 后直接运行带 --password-stdin 的 login 命令凭证会被自动存储。关键在于无论哪种方式密码的持久化存储环节都已经从明文的config.json转移到了 GPG 加密的pass存储中。5. 高级配置、管理与故障排查一套系统要稳健运行离不开日常的管理和问题的排查。5.1 配置多用户或团队协作如果你的服务器需要多个用户使用 Docker或者你需要与团队共享私有仓库的凭证pass结合 Git 和 GPG 密钥子密钥Subkey是个好方案。导出公钥将你的 GPG 公钥分发给其他服务器或团队成员。gpg --export --armor YOUR_KEY_ID team-public-key.asc在其他机器上导入公钥并信任gpg --import team-public-key.asc gpg --edit-key YOUR_KEY_ID # 在 gpg 提示符下输入 trust然后选择信任级别例如 5 绝对信任最后 save。初始化共享的 pass 存储库可以将~/.password-store目录初始化为一个 Git 仓库并推送到一个安全的内部 Git 服务器。其他成员克隆后用你的公钥加密的密码文件他们也能解密如果你将他们的公钥也加入信任并加密。# 在初始机器上 cd ~/.password-store git init git add . git commit -m Initial password store # 添加远程仓库并推送 git remote add origin your-git-repo-url git push -u origin main # 在其他机器上 git clone your-git-repo-url ~/.password-store pass init YOUR_KEY_ID # 使用相同的密钥ID初始化5.2 日常维护命令列出所有 Docker 相关凭证pass ls | grep -i docker查看某个凭证的详细信息pass DockerHub/docker.io更新一个密码直接使用pass insert覆盖原有路径或使用pass edit需要配置$EDITOR环境变量。pass insert -m DockerHub/docker.io删除一个凭证pass rm DockerHub/docker.io # 同时你可能需要手动清理 Docker 缓存中的旧认证信息 docker logout registry.hub.docker.com5.3 常见问题与排查技巧实录即使方案再完美实践中也难免踩坑。下面是我遇到过的几个典型问题及解决方法。问题一执行docker login后提示Error saving credentials: error storing credentials - ...: pass store is uninitialized原因pass存储库没有正确初始化或者 Docker 找不到docker-credential-pass。排查确认pass init YOUR_KEY_ID已成功执行。检查~/.password-store/.gpg-id文件是否存在且内容正确。确认docker-credential-pass已在PATH中。which docker-credential-pass应返回路径。检查~/.docker/config.json中credsStore: pass的拼写是否正确。尝试手动测试 helperecho https://index.docker.io/v1 | docker-credential-pass get。如果提示未初始化可能需要先执行一次pass insert任意内容来激活存储。问题二在 CI 脚本中非交互式运行时docker pull失败提示unauthorized: authentication required原因CI 环境是全新的没有 GPG 私钥或者有私钥但无法非交互式输入密码短语Passphrase。解决方案方案A推荐更安全在 CI 环境中使用特定于仓库的访问令牌Token而非账户密码并结合 Docker 的--password-stdin登录。令牌可以设置有效期和权限风险更低。登录后凭证会被缓存一段时间足够完成本次构建。方案B适用于受控的私有环境为 CI 创建一个无密码短语的 GPG 子密钥。# 在主密钥上创建子密钥在安全的环境下操作 gpg --edit-key YOUR_KEY_ID # 在 gpg 提示符下 addkey # 选择密钥类型和大小例如 RSA仅用于加密 # 设置有效期例如 1年 # **关键当提示输入密码短语时直接回车留空**。 save # 导出这个无密码的子密钥对 gpg --export-secret-subkeys --armor ci-subkey-private.asc # 在 CI 服务器上导入这个子私钥 gpg --import ci-subkey-private.asc # 初始化 pass 时使用主密钥ID但解密时会尝试所有可用的私钥包括这个无密码的子密钥。 pass init YOUR_KEY_ID警告无密码的私钥极其危险一旦泄露其加密的所有内容都将失守。务必仅在高度受控、 ephemeral临时的 CI 环境中使用并严格限制该密钥的访问范围和有效期。问题三pass命令执行缓慢原因GPG 需要生成随机数熵在虚拟机或云服务器上熵可能不足。解决安装haveged或rng-tools来增加熵。sudo yum install -y haveged sudo systemctl enable --now haveged问题四如何迁移现有的明文凭证到 pass如果你已经有很多仓库的凭证以 base64 形式存储在~/.docker/config.json的auths字段里可以按以下步骤安全迁移备份旧配置cp ~/.docker/config.json ~/.docker/config.json.backup逐一退出并重新登录# 查看当前已登录的仓库 cat ~/.docker/config.json | jq -r .auths | keys[] # 如果没有 jq可以手动查看 # 对每个仓库执行 logout 再 login docker logout registry1.example.com docker login registry1.example.com在重新登录的过程中由于已经配置了credsStore: pass新凭证会自动存入pass。验证迁移后确认新的~/.docker/config.json中不再有auths字段或者auths字段为空对象{}同时credsStore设置为pass。删除备份确认所有操作正常后安全地删除备份文件rm ~/.docker/config.json.backup。通过以上步骤我们不仅实现了一个安全的 Docker 凭证存储方案更构建了一套基于开源工具、可审计、可扩展的密码管理基础设施。它让我们的 CentOS 服务器在容器化道路上安全基础更加牢固。记住安全往往不在于使用多么高深莫测的技术而在于是否坚持执行那些已知的、有效的最佳实践。告别密码裸奔从今天这次配置开始。