Ubuntu系统从20.04开始,apt-key命令被官方标记为弃用(deprecated),取而代之的是将第三方软件源的GPG公钥直接存放在/usr/share/keyrings/目录下,并在sources.list或sources.list.d/中通过signed-by参数指定密钥文件路径。这一变化的核心原因是:传统apt-key add将所有密钥统一放入/etc/apt/trusted.gpg.d/,缺乏细粒度控制,存在安全隐患。现在的做法是"一个源对应一个密钥文件",权限更细、管理更清晰、安全更可控。如果你还在用apt-key add命令添加软件源密钥,系统会弹出警告,而且未来版本可能直接移除该命令的支持。下面我会从原理、迁移方法、日常维护、故障排查四个维度,把这件事彻底讲透。
一、为什么apt-key被淘汰?底层逻辑讲清楚
apt-key的工作方式是把所有导入的公钥合并到一个全局信任数据库里。问题在于,这个数据库里的密钥一旦被导入,就对系统所有软件源生效,你无法针对某个特定源做"只信任这一个"的限制。假设你导入了一个第三方源的密钥,这个密钥理论上可以被用来签名任意软件包,即使它本来只应该为一个源服务。这种"一刀切"的信任模型在安全审计中是不合格的。
新方案的逻辑是:每个第三方源拥有独立的密钥文件,存放在/usr/share/keyrings/下,文件名通常跟软件源名称一致。然后在/etc/apt/sources.list.d/对应的.list文件中,用[signed-by=/usr/share/keyrings/xxx.gpg]字段明确绑定。这样做的好处有三点:第一,密钥和源一一对应,不会越权;第二,密钥文件权限可以设为644(root所有),普通用户无法篡改;第三,删除某个源时,直接删对应的密钥文件即可,不会影响其他源。
二、从apt-key迁移到signed-by的完整步骤
如果你的系统里已经有通过apt-key添加的旧密钥,需要做一次清理和迁移。具体操作如下:
首先,查看当前系统中所有已导入的apt密钥:
sudo apt-key list
输出会显示每个密钥的指纹(fingerprint)、过期时间和所属UID。你需要记录下每个密钥对应的软件源名称。比如你看到"Docker"的密钥,就要找到Docker的官方源地址。
然后,导出每个密钥到独立文件:
sudo apt-key export <指纹最后8位> | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
这里的指纹最后8位可以从apt-key list的输出中获取。导出后,设置正确权限:
sudo chmod 644 /usr/share/keyrings/docker.gpg
接下来,编辑或创建对应的源列表文件,例如/etc/apt/sources.list.d/docker.list:
deb [signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu jammy stable
最后,删除旧的apt-key条目(可选,但建议清理):
sudo apt-key del <指纹最后8位>
执行完以上步骤后,运行sudo apt update验证是否正常工作。如果没有警告信息,说明迁移成功。
三、新增第三方源时的标准操作流程
从零开始添加一个新的第三方源,现在的标准流程是三步走:下载密钥、保存密钥、配置源文件。以添加NodeSource的Node.js 20.x源为例:
第一步,下载并保存GPG公钥:
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/nodesource.gpg
第二步,创建源列表文件:
echo "deb [signed-by=/usr/share/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
第三步,更新并安装:
sudo apt update sudo apt install nodejs
这个流程适用于绝大多数第三方源,包括MongoDB、Grafana、HashiCorp等。核心原则就是:永远不要再用apt-key add,而是手动把密钥存到/usr/share/keyrings/,然后在源配置里显式指定。
四、密钥环的日常维护与安全检查
密钥文件放在/usr/share/keyrings/下,并不意味着你可以完全不管。以下是几个必须定期执行的维护动作:
1. 检查密钥是否过期。GPG密钥都有有效期,过期后系统会在apt update时报错。查看密钥信息:
gpg --no-default-keyring --keyring /usr/share/keyrings/docker.gpg --list-keys
如果显示[expires: 2024-xx-xx],说明需要更新。去软件源官网下载新的公钥文件,覆盖旧文件即可。
2. 定期清理不再使用的源和密钥。如果你卸载了某个软件,记得同时删除对应的.list文件和.gpg文件:
sudo rm /etc/apt/sources.list.d/old-repo.list sudo rm /usr/share/keyrings/old-repo.gpg sudo apt update
3. 验证密钥完整性。确保密钥文件没有被篡改,可以对比官方提供的指纹值:
gpg --no-default-keyring --keyring /usr/share/keyrings/docker.gpg --fingerprint
输出的指纹应该和官方文档公布的一致。如果不一致,说明密钥可能被中间人替换,需要立即重新下载。
4. 权限审计。确保所有密钥文件的权限是644,属主是root:
ls -la /usr/share/keyrings/
如果发现某个文件权限是777或者属主不是root,说明存在安全风险,需要立即修正。
五、常见问题与故障排查
问题一:apt update报错"NO_PUBKEY XXXXXXXX"。这说明系统找不到对应的公钥。解决方法是重新下载该密钥并存到/usr/share/keyrings/,然后在源文件中添加signed-by参数。如果是旧系统遗留问题,也可以临时用apt-key add(虽然不推荐,但能救急)。
问题二:更新后提示"InRelease is not signed"或签名验证失败。通常是密钥过期或源地址变更导致。先确认密钥是否过期,再确认源URL是否正确。有些源会更换签名密钥,需要去官网查看迁移说明。
问题三:多个源使用同一个密钥文件。这在技术上是允许的,但不推荐。如果其中一个源被入侵或密钥泄露,所有使用该密钥的源都会受影响。最佳实践是每个源独立密钥。
问题四:系统升级后apt-key命令完全消失。在Ubuntu 24.04及更高版本中,apt-key可能被彻底移除。如果遇到这种情况,所有密钥管理必须通过/usr/share/keyrings/方式完成,没有退路。提前做好迁移准备是关键。
六、进阶建议:自动化管理与合规性
对于运维多台Ubuntu服务器的场景,建议使用Ansible或Shell脚本批量管理密钥文件。将每个源的密钥下载、存放、配置源文件这三步写成标准化脚本,纳入配置管理体系。这样可以保证所有服务器的密钥状态一致,避免手动操作带来的遗漏和错误。
从合规角度看,很多企业安全审计要求"最小权限原则"和"可追溯性"。新的密钥环方案天然满足这两点:每个密钥只服务于特定源(最小权限),密钥文件有明确的文件名和路径(可追溯)。如果你的环境需要通过等保或ISO27001审计,这套方案是加分项而不是减分项。
最后总结一句:apt-key的淘汰不是功能的缺失,而是安全模型的升级。拥抱signed-by方案,把密钥管理做细、做实、做规范,才是Ubuntu系统长期稳定运行的正确姿势。不要等到系统报错才去处理,现在就检查你的/usr/share/keyrings/目录,把该迁移的迁移,该清理的清理。
