SSH 登录下解锁 GNOME Keyring 的两种方法
八月 11, 2026 [网络与安全] #SSH #gnome-keyring #LinuxSSH 登录下解锁 GNOME Keyring
背景
通过 SSH(无图形会话)远程登录一台 GNOME 桌面机器时,gnome-keyring-daemon 的 login collection 通常处于锁定状态——它只在用户通过 GDM/PAM 图形登录时自动解锁。
锁定的后果之一:gnome-remote-desktop 这类依赖 libsecret 同步读取凭据的程序,在初始化时调用 secret_service_async_initable_init_async 永不返回,导致 RDP/VNC 服务卡死、不监听端口。
判断 keyring 是否锁定
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
busctl --user get-property org.freedesktop.secrets \
/org/freedesktop/secrets/collection/login \
org.freedesktop.Secret.Collection Locked
# b true → 锁定
# b false → 已解锁
注意:SSH 会话默认可能没有 DBUS_SESSION_BUS_ADDRESS,必须先指到用户会话总线(路径中的 1000 是 uid,按实际替换)。
方法一:gnome-keyring-daemon --unlock(推荐)
gnome-keyring-daemon 自带 --unlock 选项,可从 stdin 读取密码,无需交互弹窗,适合 SSH:
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
echo '你的keyring密码' | gnome-keyring-daemon --unlock \
--control-directory=/run/user/1000/keyring
--control-directory 必须与正在运行的 keyring 实例一致(通常是 /run/user/<uid>/keyring),否则会起一个新的 daemon 而不是解锁现有实例。
方法二:Secret Service Unlock + Prompt
标准 D-Bus 流程,调用 org.freedesktop.Secret.Service.Unlock 拿到 prompt 路径,再用 Prompt.Complete 提交密码:
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
import dbus
bus = dbus.SessionBus()
svc = bus.get_object('org.freedesktop.secrets', '/org/freedesktop/secrets')
iface = dbus.Interface(svc, 'org.freedesktop.Secret.Service')
objects, prompt = iface.Unlock(dbus.Array(
[dbus.ObjectPath('/org/freedesktop/secrets/collection/login')],
signature='o'))
if prompt != '/':
p = bus.get_object('org.freedesktop.secrets', prompt)
dbus.Interface(p, 'org.freedesktop.secrets.Prompt').Complete('你的keyring密码')
关键:密码是哪一个?
- login keyring 的密码是创建 keyring 时设置的那一个,通常是用户的图形登录密码
- 不是 RDP 凭据、sudo 密码或其他应用密码
- 密码不对时 unlock 静默失败,
Locked仍为b true(实测错误的 keyring 密码均失败)
修改 / 重置 keyring 密码(SSH)
unlock 的前提是密码正确;如果密码忘了,或想设成一个已知密码,SSH 下也有办法,无需图形界面。
修改密码(知道当前密码)
方式 A:GUI(需要图形桌面会话,如 Seahorse)
在桌面上打开「密码和密钥」(Seahorse)→ 左侧「密码」→ 右键 login → 「更改密码」,输入旧密码 + 新密码即可。
SSH 下想用 GUI 的话,可以
ssh -X/ssh -Y转发 X11,或借助远程桌面的图形会话。
方式 B:纯 SSH 无 GUI
用 Secret Service 的 ChangeWithPrompt 方法,走 D-Bus,流程和「方法二」类似:
import dbus
bus = dbus.SessionBus()
col = bus.get_object('org.freedesktop.secrets',
'/org/freedesktop/secrets/collection/login')
iface = dbus.Interface(col, 'org.freedesktop.Secret.Collection')
old = '当前keyring密码' # keyring 已解锁时可以为空字符串
new = '新密码'
prompt = iface.ChangeWithPrompt('/', old, new)
if prompt != '/':
p = bus.get_object('org.freedesktop.secrets', prompt)
dbus.Interface(p, 'org.freedesktop.secrets.Prompt').Complete(new)
ChangeWithPrompt 返回 / 表示直接改成功;返回其他路径时需按「方法二」的方式 Prompt.Complete 确认。改完后,--unlock 用的密码也要换成新密码。
重置密码(忘记密码)
密码忘了无法找回,keyring 里保存的凭据会一并丢失,只能重建:
mv ~/.local/share/keyrings/login.keyring ~/.local/share/keyrings.bak
下次使用时 gnome-keyring-daemon 会创建一个新的空 login keyring;之后若图形登录,PAM 会把它的密码设回当前登录密码。
一个常见坑
SSH 下 passwd 改了账户密码,keyring 密码不会跟着变——pam_gnome_keyring 只在图形登录时同步。所以会出现「账户密码正确、--unlock 却失败」,此时 keyring 密码仍是改密码前的那个,需要用旧密码先解锁再改。
验证
busctl --user get-property org.freedesktop.secrets \
/org/freedesktop/secrets/collection/login \
org.freedesktop.Secret.Collection Locked # b false = 成功
解锁后,被卡住的 gnome-remote-desktop 守护进程需重启才能继续初始化:
systemctl --user restart gnome-remote-desktop.service
总结
- SSH 下解锁 keyring 用
echo '密码' | gnome-keyring-daemon --unlock --control-directory=/run/user/<uid>/keyring即可 - 前提是密码正确,且
DBUS_SESSION_BUS_ADDRESS与--control-directory都指向现有会话实例 - 改密码用
ChangeWithPrompt,忘了密码只能删login.keyring重建(凭据全丢) - 若只是排查 gnome-remote-desktop 卡死,先确认 keyring 是否锁定,再决定是否解锁还是改用不依赖 keyring 的配置