GNOME/Keyring
GNOME Keyring 是“GNOME 中一组用于存储机密、密码、密钥、证书,并将其提供给应用程序使用的组件”。
它提供了 org.freedesktop.secrets,这是一个 API,允许客户端应用借助运行在用户登录会话中的服务来安全地存储机密。
安全性
防御恶意应用
过去曾报告过一个关于 GNOME/Keyring API 行为的安全问题(即 CVE-2018-19358)。只要钥匙环处于解锁状态,任何应用都能轻易读取任何机密。而如果用户已登录,那么登录/默认钥匙环就是解锁的。现有的 D-Bus 防护机制(涉及 busconfig 和 policy XML 元素)默认并未启用,而且就算启用也很容易被绕过。
GNOME 项目不认同这份漏洞报告,因为按照他们声明的安全模型,不应允许不可信的应用与 secret service 通信。
通过行为规范的沙箱(例如未添加额外权限的 Flatpak)运行的应用,对会话总线只有经过过滤的访问权限。
会话锁定时钥匙环并未锁定
会话锁定时,钥匙环并不会自动锁定。[1] 这意味着密码仍留在内存中,从而使系统暴露于 DMA 攻击之下。
安装
gnome-keyring包 是 gnome包组 组的成员,因此在运行 GNOME 的系统上通常已经存在。在其他情况下,也可以单独安装该软件包。还应安装 libsecret包,以便让其他应用访问你的钥匙环。虽然 libgnome-keyringAUR 已被弃用(并由 libsecret 取代),但某些应用可能仍然需要它。
gnome-keyring-daemon 会在登录时通过 systemd 用户服务自动启动。它也可以按需通过套接字启动。
与 GNOME Keyring 相关的其他实用工具包括:
- secret-tool — 从命令行访问 GNOME Keyring(以及任何其他实现了 DBus Secret Service API 的服务)。
- lssecret — 使用 libsecret 列出所有机密条目(例如 GNOME Keyring)。
用图形界面管理
你可以使用 Seahorse 管理 GNOME Keyring 的内容;请安装 seahorse包 软件包。
钥匙环的密码(例如默认钥匙环 “Login”)可以修改,甚至可以移除。更多信息见 GNOME 帮助中的 创建新钥匙环 和 更新钥匙环密码。
使用钥匙环
PAM 模块 pam_gnome_keyring.so 会部分初始化 GNOME Keyring,并在该过程中解锁 login 钥匙环。gnome-keyring-daemon 会通过 systemd 用户服务自动启动。
PAM 步骤
- 要在自动登录的情况下实现自动解锁,可以把钥匙环的密码设为空。请注意,这种情况下钥匙环的内容将以未加密形式存储。
- 另一种做法是,如果使用 GDM 和 LUKS,当钥匙环密码与 LUKS 密码一致时,GDM 可以解锁你的钥匙环。为此,你需要在 mkinitcpio.conf 中使用 systemd 初始化,并设置相应的内核参数,同时应确保系统的实时时钟设为 UTC 而非本地时间(见 [2])。更多细节见 [3]。
- 如果你希望跳过 PAM 这一步,那就必须手动或以其他方式解锁钥匙环。参见#在桌面环境(KDE、GNOME、XFCE……)之外使用 gnome-keyring-daemon和 GnomeKeyring wiki。
使用显示管理器时,多数情况下钥匙环开箱即用。GDM、LightDM、LXDM 和 SDDM 已经带有必要的 PAM 配置。对于不会自动解锁钥匙环的显示管理器,请编辑对应的文件,而不是下文提到的 /etc/pam.d/login。
使用基于控制台的登录方式时(即不使用显示管理器),请编辑 /etc/pam.d/login:
在 auth 部分的末尾添加 auth optional pam_gnome_keyring.so,并在 session 部分的末尾添加 session optional pam_gnome_keyring.so auto_start。
/etc/pam.d/login
#%PAM-1.0 auth required pam_securetty.so auth requisite pam_nologin.so auth include system-local-login auth optional pam_gnome_keyring.so account include system-local-login session include system-local-login session optional pam_gnome_keyring.so auto_start
使用指纹登录时解锁
使用 fprintd 进行指纹认证时不会设置 PAM_AUTHTOK:读取器返回的是判定结果,而不是密码。因此 pam_gnome_keyring.so 没有可用于解锁 login 钥匙环的东西,第一个请求机密的程序便会提示输入密码 [4]。任何不产生账户密码的认证方式都是如此。
可以考虑的做法:
- 在会话的首次提示中输入账户密码。此后该会话余下的时间里钥匙环都保持解锁。
- 按#PAM 步骤中所述,把 login 钥匙环的密码设为空。此时钥匙环内容将以未加密形式存储。
- 用一个在
pam_gnome_keyring.so之前运行的 PAM 模块把PAM_AUTHTOK设为钥匙环密码。该密码存放在哪里、由什么保护,正是这类实现之间的区别所在。
SSH 密钥
GNOME Keyring 可以充当 ssh-agent 的包装层。在这种模式下,每次需要解锁 SSH 密钥时,它都会显示一个图形化密码输入对话框。该对话框带有一个记住所输入密码的复选框,若勾选,那么只要你的登录钥匙环处于解锁状态,今后就能完全无密码地使用该密钥。
自 1:46 版起,gnome-keyring-daemon 的构建中默认禁用 SSH 功能。该功能已被迁移到 /usr/lib/gcr-ssh-agent,它是 gcr-4包 软件包的一部分。
配置 gcr
启用并启动 gcr-ssh-agent.socket 这个 systemd 用户单元。
该单元启动后,会创建套接字文件 $XDG_RUNTIME_DIR/gcr/ssh。
如果 gcr-ssh-agent.socket 单元处于活动状态,则无需手动配置 SSH_AUTH_SOCK 环境变量。当用户注销并重新登录时,SSH_AUTH_SOCK 环境变量的值会被设为 $XDG_RUNTIME_DIR/gcr/ssh。
使用
你可以运行
$ ssh-add -L
来列出正在运行的 agent 中已加载的 SSH 密钥。这有助于确认你启动了正确的服务,并正确设置了 SSH_AUTH_SOCK。
要把口令永久保存到钥匙环中,请使用 seahorse包 软件包提供的 ssh-askpass:
$ /usr/lib/seahorse/ssh-askpass my_key
要从其他目录手动添加 SSH 密钥:
$ ssh-add ~/.private/id_ed25519 Enter passphrase for ~/.private/id_ed25519:
~/.ssh/id_ed25519.pub)。另外,请确保公钥文件名为私钥文件名加上 .pub(例如 my_key.pub)。要禁用所有手动添加的密钥:
$ ssh-add -D
禁用
如果你希望改用其他 SSH agent(例如直接使用 ssh-agent,或使用 gpg-agent),最好禁用 GNOME Keyring 的 ssh-agent 包装层。这样做并非严格必需,因为每个 agent 监听的套接字不同,可以用 SSH_AUTH_SOCK 在它们之间选择,但这能让排查问题更容易。请注意,GNOME 的实现不支持许多脚本特性,例如 BatchMode [5]。
要禁用 gcr-ssh-agent,请确保 gcr-ssh-agent.socket 和 gcr-ssh-agent.service 在 systemd 中都已禁用并停止。
提示与技巧
与应用程序集成
锁定钥匙环
$ dbus-send --session --dest=org.freedesktop.secrets \ --type=method_call \ /org/freedesktop/secrets \ org.freedesktop.Secret.Service.Lock \ array:objpath:/org/freedesktop/secrets/collection/login
该命令执行一次 D-Bus 方法调用,以锁定 login 钥匙环。或者,如果你想使用图形界面,也可以用 Seahorse 锁定钥匙环。
清空口令
$ gnome-keyring-daemon -r -d
该命令会启动 gnome-keyring-daemon,并关闭此前已经在运行的实例。
Git 集成
当你通过 HTTPS 推送时,GNOME keyring 与 Git 配合使用会很有用。libsecret包 软件包需要安装,该功能才可用。
配置 Git 使用 libsecret 助手:
$ git config --global credential.helper /usr/lib/git-core/git-credential-libsecret
下次运行 git push 时,如果你的钥匙环尚未解锁,系统会要求你解锁它。
GnuPG 集成
有几个使用 GnuPG 的应用需要设置 pinentry-program。设置以下内容即可使用 GNOME 3 pinentry,让 GNOME Keyring 来管理口令提示。
~/.gnupg/gpg-agent.conf
pinentry-program /usr/bin/pinentry-gnome3
另一种做法是强制 GPG 使用 loopback,这样应该就能在应用内输入口令。
重命名钥匙环
钥匙环的显示名称(即 Seahorse 和 file 命令中显示的名称)可以通过[更改未加密钥匙环文件中 display-name 的值来修改]。钥匙环通常存放在 ~/.local/share/keyrings/ 中,扩展名为 .keyring。
用户密码变化时自动更改钥匙环密码
向 /etc/pam.d/passwd 中追加 password optional pam_gnome_keyring.so:
/etc/pam.d/passwd
... password optional pam_gnome_keyring.so
在桌面环境(KDE、GNOME、XFCE……)之外使用 gnome-keyring-daemon
启动
如果你使用 sway、i3,或任何不会执行
/etc/xdg/autostart/gnome-keyring-*.desktop/etc/X11/xinit/xinitrc.d/50-systemd-user.sh
的窗口管理器,那么你的窗口管理器需要在启动时执行以下命令。这些命令不必按特定顺序执行。
dbus-update-activation-environment DISPLAY XAUTHORITY WAYLAND_DISPLAY
或者
dbus-update-activation-environment --all
该命令会把环境变量从窗口管理器传递给会话 dbus。若不执行,就无法通过 DBus 触发图形化的提示框。例如,Seahorse 的密码提示就依赖于此。
之所以需要这样做,是因为会话 dbus 在图形环境启动之前就已经启动,因此会话 dbus 并不知道你处在哪个图形环境中。必须有某个东西把描述图形环境的环境变量传给会话 dbus,让它了解当前的图形环境。
gnome-keyring-daemon --start --components=secrets
登录期间,PAM 会启动 gnome-keyring-daemon --login,它负责用登录密码让 gnome-keyring 保持解锁状态。如果 gnome-keyring-daemon --login 在几分钟内没有连接到会话 dbus,gnome-keyring-daemon --login 就会退出。如果在窗口管理器中针对会话 dbus 启动了 gnome-keyring-daemon --start ...,那么 gnome-keyring-daemon --login 就会连接到会话 dbus。如果你的登录会话没有在 gnome-keyring-daemon --login 退出前启动 gnome-keyring-daemon --start ...,你也可以在 gnome-keyring-daemon --login 退出之前,先运行任何使用 gnome-keyring 或 secret service API 的程序。
GNOME Keyring XDG 门户
GNOME Keyring 提供一个 XDG 门户后端(例如可供通过 Flatpak 沙箱化的应用使用)。要使其在 GNOME 之外工作,必须配置为使用它。有几种做法。
配置用户级的 Secrets 门户
避免修改系统文件的方法是,在 $XDG_CONFIG_HOME/xdg-desktop-portal/$XDG_CURRENT_DESKTOP-portals.conf 中把 gnome-keyring 配置为首选的 Secrets 门户。例如,要把 sway 配置为使用 gnome-keyring 作为 org.freedesktop.impl.portal.Secret 的首选门户:
~/.config/xdg-desktop-portal/sway-portals.conf
[preferred] default=wlr;gtk org.freedesktop.impl.portal.Secret=gnome-keyring
修改 gnome-keyring.portal
另一种方法是修改 UseIn 键,把你的桌面环境加入 /usr/share/xdg-desktop-portal/portals/gnome-keyring.portal 配置文件。例如,要加入 sway:
/usr/share/xdg-desktop-portal/portals/gnome-keyring.portal
[portal] DBusName=org.freedesktop.secrets Interfaces=org.freedesktop.impl.portal.Secret UseIn=gnome;sway
关于 XDG 桌面门户后端的更多信息,见 XDG 桌面门户#后端。
故障排除
密码没有被记住
如果你在登录后被要求输入密码,并且发现密码没有被保存,那么你可能需要创建/设置一个默认钥匙环。要使用 Seahorse(也称“密码和密钥”)完成此操作,见 GNOME 帮助中的 创建新钥匙环 和 更改默认钥匙环。
重置钥匙环
如果你收到以下错误信息:“The password you use to login to your computer no longer matches that of your login keyring”,你需要更改登录钥匙环密码。
或者,你可以从 ~/.local/share/keyrings/ 中删除 login.keyring 和 user.keystore 文件。请注意,这会永久删除所有已保存的密钥。删除这些文件后,只需注销再重新登录即可。
Unable to locate daemon control file
登录后,日志中可能会出现以下错误:
gkr-pam: unable to locate daemon control file
如果没有其他相关问题,这条消息“可以安全地忽略” [6]。
No such secret collection at path: /
如果你尝试用 Seahorse 添加新钥匙环,可能会因以下原因收到此错误:
-
~/.local/share/keyrings/目录不存在。若缺失请创建它。 - 使用了自定义的
~/.xinitrc。添加以下一行可能可以解决 [7]
~/.xinitrc
source /etc/X11/xinit/xinitrc.d/50-systemd-user.sh
终端提示 “discover_other_daemon: 1”
这是因为 gnome-keyring-daemon 被第二次启动了。既然该守护进程已经随附了 systemd 服务,就无需再以其他方式启动它。所以请确保从 .zshenv、.bash_profile、.xinitrc、config.fish 或类似文件中删除启动命令。或者,你也可以禁用 gnome-keyring-daemon.service 和 gnome-keyring-daemon.socket 这些用户单元。
钥匙环初始化不正确
这有几种症状:
- SSH 或 Git 之类的程序在等待钥匙环提供密码时挂起,最终超时并报出 “agent refused operation” 之类的错误。
- Seahorse 不显示任何钥匙环,而且手动创建一个名为 “login” 的钥匙环似乎不起作用。
- Seahorse 的输出中出现以下错误信息:
couldn't load all secret collections: No such secret collection at path: /org/freedesktop/secrets/collection/login
要解决此问题,请执行以下操作:
-
重启
gnome-keyring-daemon.service这个 systemd 用户单元。这应当能正确初始化 login 钥匙环。 - 如果使用的话,重启
gcr-ssh-agent.service这个 systemd 用户单元。其他 agent 可能也需要重启。
如果这样仍无法解决问题,可以考虑重置钥匙环。
SSH agent 不可用
症状:
$ ssh-add -L
Error connecting to agent: Connection refused
请确保 gcr-ssh-agent.socket 用户单元已被启用并启动,并且 gnome-keyring-daemon 的套接字和服务用户单元也已启用并启动:
{service,socket} 使用 shell 的花括号展开。No Process Capabilities, Insecure Memory Might Get Used
如果看到以下错误 gnome-keyring-daemon: no process capabilities, insecure memory might get used,这意味着钥匙环可能会被保存到交换文件/分区中。这是一个安全问题,因为他人可能在没有适当授权的情况下读取并提取这些机密。解决方法是让内核不要这样做,但 gnome-keyring-daemon 需要具备相应的权限才行。
运行以下命令,赋予 gnome-keyring-daemon 适当的内存锁定权限:
# setcap cap_ipc_lock=+ep /usr/bin/gnome-keyring-daemon