SSH 登录方案 —— 使用 systemd user unit 管理 ssh-agent

背景

传统方式下,ssh-agent 通常由桌面环境或 shell 启动,依赖 X 会话。离开图形环境(如纯 TTY、SSH 跳板机)时,agent 不会自动运行,需要手动处理。

OpenSSH 9.4p1-3 开始,openssh 包提供了原生的 ssh-agent.service 用户单元,由 systemd 接管生命周期,随用户登录启动,与 X 无关。

配置步骤

1. 启用 ssh-agent 用户服务

systemctl --user enable --now ssh-agent.service

2. 设置环境变量

SSH_AUTH_SOCK 指向 systemd 管理的 socket。

Shell 配置(添加到 ~/.bashrc~/.zshrc):

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"

systemd 环境(确保 SSH_AUTH_SOCK 对 systemd user units 也可见):

mkdir -p ~/.config/environment.d

创建 ~/.config/environment.d/ssh-agent.conf

SSH_AUTH_SOCK=${XDG_RUNTIME_DIR}/ssh-agent.socket

~/.config/environment.d/*.conf 中的变量由 systemd 在用户登录时自动导入,所有 systemd user 服务都能继承该环境变量,无需额外操作。

3. 自动添加密钥到 agent

编辑 ~/.ssh/config,全局启用自动添加:

Host *
  AddKeysToAgent yes

这样,首次使用 SSH 连接时,私钥会自动加载到 agent,后续连接无需重复输入密码。

验证

# 检查 agent 是否运行
systemctl --user status ssh-agent.service

# 查看已加载的密钥
ssh-add -l

进阶方案 —— KeePassXC 代理 SSH Agent

KeePassXC 是一款跨平台开源密码管理器,原生支持与 SSH Agent 集成。私钥以附件形式加密存储在数据库中,解锁数据库时自动加载到 agent,锁定或关闭时自动移除,实现按需使用。

为什么用密码管理器管理 SSH 密钥

密钥文件默认存在 ~/.ssh/ 目录,一旦系统被入侵,私钥可能被窃取。即使设置了密码,每次使用都要手动输入,体验繁琐。

KeePassXC 将密钥对加密存储在 KDBX 数据库中,使用时通过主密码解锁,用完后锁定即卸载密钥。既免去了密钥文件管理、重复输入密码的麻烦,又提高了安全性。

保存私钥到 KeePassXC

创建 SSH 专用群组后,新建条目:

  1. 条目标签:标题/用户名可任意填写(仅用于备忘),密码填入创建密钥时设置的密码
  2. 高级标签:附件区域点击「添加文件-从磁盘加载」,将公钥和私钥都添加上
  3. SSH 代理标签
    • 勾选「在打开或解锁数据库时,向代理添加密钥」
    • 勾选「数据库关闭或锁定时,从代理中删除密钥」
    • 私钥区域选择附件中对应的私钥文件
    • Windows 不要勾选「使用此密钥时请求用户确认」(不支持该特性)

保存后,密钥便安全地托管在 KeePassXC 中。

集成 SSH Agent

打开 KeePassXC 工具 → 设置 → SSH 代理

  • 勾选「启用 SSH 代理集成」
  • 代理类型选择「使用 OpenSSH」(推荐,Pageant 仅 PuTTY 生态可用)

保存后返回该页面,若显示 SSH 代理连接工作正常 则表示集成成功。Windows 下若提示 代理未在运行,需先启动 ssh-agent 服务。

验证

锁定 KeePassXC,打开终端执行:

ssh-add -l
# 输出: The agent has no identities.

解锁 KeePassXC 后再次执行,将显示已加载的密钥指纹。

日常使用:SSH Config 配合公钥匹配

由于私钥不再保存在文件系统中,IdentityFile 需指向对应的公钥文件。SSH 会通过公钥指纹从 agent 中找到已加载的私钥。

Host github.com
    HostName github.com
    User git
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_ed25519_github.pub

Host myserver
    HostName 192.168.1.100
    User ubuntu
    IdentitiesOnly yes
    IdentityFile ~/.ssh/id_ed25519_server.pub

参考