SSH 密钥

来自 ArchWiki
(重定向自 SSH agent

此文章或章节需要扩充。

原因: 导言和背景章节忽略了服务器的角度。(在 Talk:SSH keys 中讨论)

SSH 密钥可以用作使用公钥加密挑战-应答身份验证向 SSH 服务器标识您身份的一种方式。基于密钥的身份验证的主要优点是,与密码身份验证相比,它不易受到暴力攻击,并且如果服务器已被入侵,您不会泄露有效的凭据(请参阅RFC 4251 9.4.4)。

此外,SSH 密钥身份验证可能比更传统的密码身份验证更方便。当与称为 SSH 代理的程序一起使用时,SSH 密钥允许您连接到一台或多台服务器,而无需记住或为每个系统输入密码。

基于密钥的身份验证并非没有缺点,可能不适用于所有环境,但在许多情况下,它可以提供一些强大的优势。对 SSH 密钥工作原理的一般理解将帮助您决定如何以及何时使用它们来满足您的需求。

本文假设您已经对安全外壳协议有基本的了解,并且已经安装openssh软件包。

背景

SSH 密钥始终成对生成,一个称为私钥,另一个称为公钥。私钥仅您知道,应安全保管。相比之下,公钥可以与您希望连接的任何 SSH 服务器自由共享。

如果 SSH 服务器在文件中有您的公钥,并且看到您请求连接,它会使用您的公钥构建并向您发送一个质询。此质询是一条加密消息,必须使用适当的响应来满足此质询,服务器才会授予您访问权限。使此编码消息特别安全的原因在于,它只能被私钥持有者理解。虽然公钥可用于加密消息,但它不能用于解密同一消息。只有您,私钥的持有者,才能正确理解质询并生成正确的响应。

这个挑战-应答阶段发生在幕后,用户不可见。只要您持有私钥(通常存储在 ~/.ssh/ 目录中),您的 SSH 客户端应该能够向服务器回复适当的响应。

私钥是受保护的秘密,因此建议以加密形式将其存储在磁盘上。当需要加密的私钥时,必须首先输入密码短语才能解密它。虽然这表面上看起来像是您正在向 SSH 服务器提供登录密码,但密码短语仅用于解密本地系统上的私钥。密码短语不会通过网络传输。

生成 SSH 密钥对

可以通过运行 ssh-keygen 命令来生成 SSH 密钥对,有关“通常被认为是足够的”以及应与几乎所有客户端和服务器兼容的内容,请参阅ssh-keygen(1) 手册页

$ ssh-keygen
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/username/.ssh/id_ed25519):
Created directory '/home/username/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_ed25519
Your public key has been saved in /home/username/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:RLy4JBv7jMK5qYhRKwHB3af0rpMKYwE2PBhALCBV3G8 username@hostname
The key's randomart image is:
+--[ED25519 256]--+
|%oooo. ..        |
|== ..o.o.        |
|==  . +o..       |
|+ o o.ooE        |
|...  *.oS        |
| o..o ..         |
|o=.. +o          |
|+o*..+o          |
|+.o+. .          |
+----[SHA256]-----+

randomart 图像OpenSSH 5.1 中引入,作为一种更简单地以可视方式识别密钥指纹的方法。

注意: 您可以使用 -a 开关来指定密码加密的 KDF 轮数。

您还可以使用 -C 开关向公钥添加可选的注释字段,以便在 ~/.ssh/known_hosts~/.ssh/authorized_keysssh-add -L 输出等位置更轻松地识别它。例如

$ ssh-keygen -C "$(whoami)@$(uname -n)-$(date -I)"

将添加一条注释,说明哪个用户在哪个机器上以及何时创建了密钥。

选择身份验证密钥类型

OpenSSH 支持几种签名算法(用于身份验证密钥),可以根据它们利用的数学特性分为两组

  1. Ed25519ECDSA,它们依赖于椭圆曲线离散对数问题 (ECDLP)。(示例)
  2. RSA,它依赖于分解两个大质数乘积的实际困难

椭圆曲线密码学 (ECC) 算法是公钥密码系统中较新的补充。它们的主要优势之一是它们能够以更小的密钥提供相同的安全级别,这使得计算密集型操作更少(更快的密钥创建、加密和解密),并降低了存储和传输要求。

DSA 密钥由于其安全漏洞而已被弃用,并且 SSH 实现正在删除对它们的支持。OpenSSH 9.8 在构建时默认不包含对 DSA 密钥的支持,Dropbear 2022.83 禁用了 DSA 密钥支持,libssh 0.11.0 完全删除了对 DSA 密钥的支持。因此,密码系统的选择在于 RSA 或两种 ECC 类型之一。

默认的 Ed25519 将为您提供最佳的安全性和良好的性能。ECDSA 比 Ed25519 慢,但比 RSA 快;对其安全性存在担忧(见下文)。RSA 密钥将为您提供与旧服务器的最佳兼容性,但它需要更大的密钥大小才能提供足够的安全性。

注意: 这些密钥仅用于验证您的身份;选择更强的密钥不会增加通过 SSH 传输数据时的 CPU 负载。
提示: 为了防止 SSH 密钥从机器泄露,可以将它们存储在FIDO/U2F 硬件身份验证器可信平台模块中。
  • Ed25519 和 ECDSA 密钥可以通过在使用特殊“安全密钥”密钥类型生成密钥时存储在 FIDO/U2F 硬件身份验证器中。请参阅#FIDO/U2F
  • 可信平台模块支持 ECDSA 和 RSA,这使得可以将 SSH 密钥密封在 TPM 内部。请参阅可信平台模块#SSH

Ed25519

Ed25519OpenSSH 6.5(2014 年 1 月)中引入:“Ed25519 是一种椭圆曲线签名方案,它提供比 ECDSA 和 DSA 更好的安全性和良好的性能”。它的主要优势在于其速度、其恒定时间运行时间(以及对侧信道攻击的抵抗力)以及其缺乏模糊的硬编码常量。[1] 另请参阅 Mozilla 开发人员关于其工作原理的这篇博客文章

它在许多应用程序和库中实现,并且是 OpenSSH 中的默认密钥交换算法(这与密钥签名不同)。

ssh-keygen(1) 默认为 Ed25519,因此无需使用 -t ed25519 选项指定它。密钥对可以简单地使用以下命令生成

$ ssh-keygen

无需设置密钥大小,因为所有 Ed25519 密钥均为 256 位。

请记住,旧的 SSH 客户端和服务器可能不支持这些密钥。

ECDSA

椭圆曲线数字签名算法 (ECDSA) 是从 OpenSSH 5.7 (2011-01-24) 到 OpenSSH 6.5 (2014-01-30) 的首选身份验证算法(密钥交换算法)。

关于它有两种担忧

  1. 政治担忧,在揭露 NSA 愿意将后门插入软件、硬件组件和已发布标准之后,NIST 生产的曲线的可靠性受到质疑;著名的密码学家 已经 表达了 NIST 曲线的设计方式的疑虑,并且自愿污染已经在过去被证明
  2. 技术担忧,关于正确实现标准的难度以及速度慢和设计缺陷,这会降低预防措施不足的实现中的安全性。

这两个担忧最好在 libssh curve25519 介绍中总结。尽管政治担忧仍然存在争议,但#Ed25519 在技术上更优越,因此应该首选,这已成为明确的共识

ECDSA 密钥对可以使用以下命令生成

$ ssh-keygen -t ecdsa

ECDSA 密钥支持三种椭圆曲线大小:256、384 和 521 位。默认值为 256 位。如果您希望生成更强的 ECDSA 密钥对,只需指定 -b 选项

$ ssh-keygen -t ecdsa -b 384

RSA

RSA 提供所有算法中最佳的兼容性,但需要更大的密钥大小才能提供足够的安全性。最小密钥大小为 1024 位,默认值为 3072(请参阅ssh-keygen(1)),最大值为 16384。

RSA 密钥对可以使用以下命令生成

$ ssh-keygen -t rsa

如果您希望生成更强的 RSA 密钥对(例如,为了防范尖端或未知攻击以及更复杂的攻击者),只需使用比默认值更高的位值指定 -b 选项

$ ssh-keygen -t rsa -b 4096

但请注意,使用更长的密钥会产生收益递减。[2][3] GnuPG FAQ 中写道:“如果您需要的安全性高于 RSA-2048 提供的安全性,那么应该转向椭圆曲线密码学,而不是继续使用 RSA。”[4]

另一方面,NSA Fact Sheet Suite B Cryptography 的最新迭代建议 RSA 的最小 3072 位模数,同时“[准备]迎接即将到来的抗量子算法过渡”。[5]

FIDO/U2F

此文章或章节需要扩充。

原因: OpenSSH 版本 8.2 添加了对 FIDO2 常驻密钥的支持,允许将 SSH 密钥存储在硬件令牌上。(在 Talk:SSH keys 中讨论)

FIDO/U2F 硬件身份验证器 支持在 OpenSSH 版本 8.2 中为上述两种椭圆曲线签名方案添加。它允许通过 USB 或其他方式连接的硬件令牌充当私钥的第二因素。

硬件令牌支持需要 libfido2

注意
  • 客户端和服务器都必须支持 ed25519-skecdsa-sk 密钥类型。
  • OpenSSH 使用中间件库与硬件令牌通信,并附带一个支持 USB 令牌的内部中间件。其他中间件可以通过 sshd_config(5) § SecurityKeyProvider 指令或 SSH_SK_PROVIDER 环境变量为 ssh-keygenssh-add 指定。

连接兼容的 FIDO 密钥后,可以使用以下命令生成密钥对

$ ssh-keygen -t ed25519-sk

通常,您需要输入 PIN 和/或轻触令牌以确认生成。连接到服务器通常需要轻触令牌,除非在生成期间使用了 -O no-touch-required 命令行选项,并且在服务器上设置了 sshd(8) § no-touch-required authorized_keys 选项。

要创建不需要触摸事件的密钥,请使用 no-touch-required 选项生成密钥对。例如

$ ssh-keygen -O no-touch-required -t ed25519-sk
注意: 并非所有硬件令牌都支持此选项。如果您使用的是 YubiKey,则 ed25519-sk 密钥类型需要固件版本 5.2.3。[6]

此外,sshd 默认拒绝 no-touch-required 密钥。要允许使用此选项生成的密钥,请在 authorized_keys 文件中为单个密钥启用它,

no-touch-required sk-ssh-ed25519@openssh.com AAAAInN... user@example.com

或通过编辑 /etc/ssh/sshd_config 为整个系统启用它

PubkeyAuthOptions none
提示: GitHubGitLab 不支持 no-touch-required

也可以使用 ecdsa-sk 密钥类型生成基于 ECDSA 的密钥对,但 #ECDSA 章节中的相关担忧仍然适用。

$ ssh-keygen -t ecdsa-sk

选择密钥位置和密码

发出 ssh-keygen 命令后,系统将提示您输入期望的私钥名称和位置。默认情况下,密钥存储在 ~/.ssh/ 目录中,并根据使用的加密类型命名。建议您接受默认名称和位置,以便本文后面的代码示例能够正常工作。

当提示输入密码短语时,如果您考虑到私钥的安全性,请选择一些难以猜测的内容。更长、更随机的密码通常会更强大,并且如果落入坏人之手,则更难破解。

也可以创建没有密码短语的私钥。虽然这可能很方便,但您需要意识到相关的风险。如果没有密码短语,您的私钥将以未加密的形式存储在磁盘上。任何获得对您的私钥文件访问权限的人都将能够在使用基于密钥的身份验证连接的任何 SSH 服务器上冒充您的身份。此外,如果没有密码短语,您还必须信任 root 用户,因为他们可以绕过文件权限,并且可以随时访问您的未加密私钥文件。

注意: 以前,私钥密码以不安全的方式编码:仅进行单轮 MD5 哈希。OpenSSH 6.5 及更高版本支持一种新的、更安全的格式来编码您的私钥。自 OpenSSH 版本 7.8 以来,此格式为默认格式。Ed25519 密钥始终使用新的编码格式。要升级到新格式,只需更改密钥的密码短语,如下节所述。

在不更改密钥的情况下更改私钥的密码

如果最初选择的 SSH 密钥密码短语不理想或必须更改,则可以使用 ssh-keygen 命令来更改密码短语,而无需更改实际密钥。这也可以用于将密码编码格式更改为新标准。

$ ssh-keygen -f ~/.ssh/id_rsa -p

管理多个密钥

如果您有多个 SSH 身份,则可以使用配置中的 HostIdentityFile 指令为不同的主机或远程用户设置不同的密钥

~/.ssh/config
Host SERVER1
   IdentitiesOnly yes
   IdentityFile ~/.ssh/id_rsa_IDENTITY1

Host SERVER2 SERVER3
   IdentitiesOnly yes
   IdentityFile ~/.ssh/id_ed25519_IDENTITY2

有关这些选项的完整描述,请参阅 ssh_config(5)

在硬件令牌上存储 SSH 密钥

SSH 密钥也可以存储在安全令牌上,例如智能卡或 USB 令牌。这样做的好处是,私钥安全地存储在令牌上,而不是存储在磁盘上。当使用安全令牌时,敏感的私钥也永远不会出现在 PC 的 RAM 中;加密操作在令牌本身上执行。加密令牌的另一个优点是它不绑定到单台计算机;它可以轻松地从计算机上移除并随身携带,以便在其他计算机上使用。

硬件令牌的示例在以下位置描述

将公钥复制到远程服务器

此文章或章节需要扩充。

原因: 如果您强制公钥身份验证,如何执行此操作? (在 Talk:SSH keys 中讨论)

生成密钥对后,您需要将公钥复制到远程服务器,以便它将使用 SSH 密钥身份验证。公钥文件与私钥文件共享相同的名称,只是附加了 .pub 扩展名。请注意,私钥不共享,并保留在本地计算机上。

简单方法

如果您的密钥文件是 ~/.ssh/id_rsa.pub,您可以简单地输入以下命令。

$ ssh-copy-id remote-server.org

如果您的用户名在远程计算机上有所不同,请务必在服务器名称前加上用户名和 @

$ ssh-copy-id username@remote-server.org

如果您的公钥文件名不是默认的 ~/.ssh/id_rsa.pub,您将收到错误消息 /usr/bin/ssh-copy-id: ERROR: No identities found。在这种情况下,您必须显式提供公钥的位置。

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub username@remote-server.org

如果 ssh 服务器正在侦听端口 22 以外的端口,请务必将其包含在主机参数中。

$ ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 221 username@remote-server.org

手动方法

默认情况下,对于 OpenSSH,公钥需要与 ~/.ssh/authorized_keys 连接。首先将公钥复制到远程服务器。

$ scp ~/.ssh/id_ecdsa.pub username@remote-server.org:

上面的示例通过 scp 将公钥 (id_ecdsa.pub) 复制到远程服务器上的主目录。不要忘记在服务器地址的末尾包含 :。另请注意,您的公钥名称可能与给出的示例不同。

在远程服务器上,如果 ~/.ssh 目录尚不存在,您需要创建它,并将您的公钥追加到 authorized_keys 文件。

$ ssh username@remote-server.org
username@remote-server.org's password:
$ install -dm700 ~/.ssh
$ cat ~/id_ecdsa.pub >> ~/.ssh/authorized_keys
$ rm ~/id_ecdsa.pub
$ chmod 600 ~/.ssh/authorized_keys

最后两个命令从服务器中删除公钥文件,并设置 authorized_keys 文件的权限,使其仅对您(所有者)可读写。

SSH 代理

如果您的私钥使用密码短语加密,则每次您尝试使用公钥身份验证连接到 SSH 服务器时,都必须输入此密码短语。每次调用 sshscp 都需要密码短语才能解密您的私钥,然后才能进行身份验证。

SSH 代理是一个程序,它缓存您解密的私钥,并代表您将其提供给 SSH 客户端程序。在这种安排中,您只需在将私钥添加到代理的缓存时提供一次密码短语。在进行频繁的 SSH 连接时,此功能非常方便。

代理通常配置为在登录时自动运行,并在您的登录会话期间持续存在。存在各种代理、前端和配置来实现此效果。本节概述了许多不同的解决方案,这些解决方案可以进行调整以满足您的特定需求。

ssh-agent

ssh-agent 是 OpenSSH 中包含的默认代理。它可以直接使用,也可以用作本节稍后提到的几个前端解决方案的后端。当 ssh-agent 运行时,它会 fork 到后台并打印必要的环境变量。例如

$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-vEGjCM2147/agent.2147; export SSH_AUTH_SOCK;
SSH_AGENT_PID=2148; export SSH_AGENT_PID;
echo Agent pid 2148;

要使用这些变量,请通过 eval 命令运行该命令。如果使用 fish shell,请改用 ssh-agent -c

$ eval $(ssh-agent)
Agent pid 2157

一旦 ssh-agent 运行,您需要将您的私钥添加到其缓存中

$ ssh-add ~/.ssh/id_ed25519
Enter passphrase for /home/user/.ssh/id_ed25519:
Identity added: /home/user/.ssh/id_ed25519 (/home/user/.ssh/id_ed25519)

如果您的私钥已加密,ssh-add 将提示您输入密码短语。一旦您的私钥已成功添加到代理,您将能够在无需输入密码短语的情况下进行 SSH 连接。

提示: 为了使所有 ssh 客户端(包括 git)在首次使用时将密钥存储在代理中,请将配置设置 AddKeysToAgent yes 添加到 ~/.ssh/config。其他可能的值是 confirmaskno(默认)。

为了自动启动代理并确保一次只运行一个 ssh-agent 进程,请将以下内容添加到您的 ~/.bashrc

if ! pgrep -u "$USER" ssh-agent > /dev/null; then
    ssh-agent -t 1h > "$XDG_RUNTIME_DIR/ssh-agent.env"
fi
if [ ! -f "$SSH_AUTH_SOCK" ]; then
    source "$XDG_RUNTIME_DIR/ssh-agent.env" >/dev/null
fi

如果尚不存在 ssh-agent 进程,这将运行一个 ssh-agent 进程,并保存其输出。如果已有一个正在运行,我们将检索缓存的 ssh-agent 输出并对其求值,这将设置必要的环境变量。解锁密钥的生命周期设置为 1 小时。

还存在许多 ssh-agent 的前端和本节稍后描述的替代代理,它们避免了这个问题。

使用 systemd 用户启动 ssh-agent

如果您希望您的 ssh 代理在您登录时运行,无论 X 是否正在运行,ssh-agent.service 实用程序已包含在 openssh 软件包中,版本为 9.4p1-3 或更高版本,可以启用用户单元

然后设置环境变量 SSH_AUTH_SOCK$XDG_RUNTIME_DIR/ssh-agent.socket

注意: 如果您使用 GNOME,此环境变量默认会被覆盖。请参阅 GNOME/Keyring#禁用

转发 ssh-agent

此文章或章节需要改进语言、wiki 语法或风格。请参阅 Help:Style 以获取参考。

原因: 这并非 ssh-agent 特有,例如 gpg-agent 使用相同的环境变量:GnuPG#转发 gpg-agent 和 ssh-agent 到远程 (在 Talk:SSH keys 中讨论)

转发本地 ssh-agent 到远程机器时(例如,通过命令行参数 ssh -A remote 或通过配置文件中的 ForwardAgent yes),重要的是远程机器不要覆盖环境变量 SSH_AUTH_SOCK。因此,如果远程机器使用先前显示的 systemd 单元来启动代理,则当用户通过 SSH 登录时,SSH_AUTH_SOCK 必须不在环境中设置。否则,转发可能会失败,并且当在远程机器上使用 ssh-add -l 检查现有密钥时,您可能会看到错误(例如:The agent has no identities)。

例如,如果使用 bash,.bashrc 可能如下所示

~/.bashrc
...
if [[ -z "${SSH_CONNECTION}" ]]; then
    export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
fi
...

通过这种方式,SSH_AUTH_SOCK 仅在当前会话不是 SSH 登录时设置。当这是一个 SSH 会话时,远程机器上的 SSH_AUTH_SOCK 然后由本地机器设置,以使转发工作。

ssh-agent 作为包装程序

启动 ssh-agent 的另一种方法(例如,在每个 X 会话中)在 UC Berkeley Labs 的 ssh-agent 教程中描述。一个基本用例是,如果您通常使用 startx 命令启动 X,您可以改为在其前面加上 ssh-agent,如下所示

$ ssh-agent startx

因此,您甚至无需考虑它,您可以将别名放在您的 .bash_aliases 文件或等效文件中

alias startx='ssh-agent startx'

这样做避免了在登录会话之间存在多余的 ssh-agent 实例的问题。只有一个实例会与整个 X 会话一起存在和消亡。

注意: ssh-askpass 需要 DISPLAYWAYLAND_DISPLAY 环境变量才能工作,因此您可能希望在 ~/.xinitrc 中运行 ssh-agent 而不是 ssh-agent startx,在 ~/.xinitrcDISPLAY 已设置。例如,您可以将 exec ssh-agent dbus-launch i3 添加到 ~/.xinitrc。或者,作为使用 ssh-agent 作为包装程序的替代方法,您可以将 eval $(ssh-agent) 添加到 ~/.xinitrc

有关如何立即将您的密钥添加到代理的想法,请参阅 关于将 x11-ssh-askpass 与 ssh-add 一起使用的注释

OpenPGP 卡 ssh-agent

此 ssh-agent 专注于 OpenPGP 卡集成。它使用存储在 OpenPGP 卡身份验证槽中的私钥。

注意: 当在运行此代理时也使用 GnuPG 时,需要将其与 pcscd 一起使用,并配置 与 pcscd 的共享访问

安装 openpgp-card-ssh-agent启用启动 openpgp-card-ssh-agent.socket 用户单元。

之后,为此代理添加相关的环境变量

export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/openpgp-card/ssh-agent.sock"

用户 PIN 码处理

OpenPGP 卡的用户 PIN 码默认通过 org.freedesktop.secrets 提供程序(例如 GNOME KeyringKeePassXCKDE Wallet)持久化。 PIN 码存储后端是可配置和可扩展的

用户 PIN 码只需为每张 OpenPGP 卡持久化一次。在第一次使用此代理的 SSH 连接之前,列出可用的 SSH 公钥并添加它们各自的卡标识符

$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJUz6VnFprMe33G88Pq8NLw3wnIKOsBg0CDrwFeUVrU6 FFFE:01234567
$ ssh-add -s FFFE:01234567
Enter passphrase for PKCS#11:
注意: 提示提到 PKCS#11,因为它是 ssh-add(1) 中的硬编码消息。但是,在这种情况下,必须输入 OpenPGP 卡用户 PIN 码。

GnuPG 代理

gpg-agent 具有 OpenSSH 代理协议模拟功能。有关必要的配置,请参阅 GnuPG#SSH 代理

Keychain

Keychain 是一个旨在帮助您轻松管理 SSH 密钥的程序,用户交互最少。它作为一个 shell 脚本实现,驱动 ssh-agentssh-add。Keychain 的一个显著特点是它可以跨多个登录会话维护单个 ssh-agent 进程。这意味着您只需在每次本地机器启动时输入一次密码。

安装

安装 keychain 软件包。

配置

警告: 截至 2015-09-26,-Q, --quick 选项具有意外的副作用,即在重新登录时(至少在使用 GNOME 的系统上),keychain 会切换到新生成的 ssh-agent,迫使您重新添加所有先前注册的密钥。

在您的 shell 配置文件中添加类似于以下行的行,例如 如果使用 Bash

~/.bashrc
eval $(keychain --eval --quiet id_ed25519 id_rsa ~/.keys/my_custom_key)
注意: 使用 ~/.bashrc 而不是上游建议的 ~/.bash_profile,因为在 Arch 上,它由登录和非登录 shell 均会读取,使其适用于文本和图形环境。有关两者之间差异的更多信息,请参阅 Bash#调用

在上面的例子中,

  • --eval 开关输出要由打开的 eval 命令评估的行;这为 SSH 客户端设置必要的环境变量,使其能够找到您的代理。
  • --quiet 将输出限制为警告、错误和用户提示。

可以在命令行中指定多个密钥,如示例所示。默认情况下,keychain 将在 ~/.ssh/ 目录中查找密钥对,但绝对路径可用于非标准位置的密钥。您也可以使用 --confhost 选项来告知 keychain 在 ~/.ssh/config 中查找为特定主机定义的 IdentityFile 设置,并使用这些路径来定位密钥。

有关为其他 shell 设置 keychain 的详细信息,请参阅 keychain --helpkeychain(1)

要测试 Keychain,只需打开一个新的终端模拟器或注销并重新登录您的会话。它应该提示您输入指定的私钥的密码(如果适用),可以使用 $SSH_ASKPASS 中设置的程序或在终端上。

由于 Keychain 在连续登录时重用相同的 ssh-agent 进程,因此您下次登录或打开新终端时应该不必输入密码。您只需在每次机器重启时输入一次密码。

提示

  • keychain 期望公钥文件与其私钥副本位于同一目录中,并带有 .pub 扩展名。如果私钥是符号链接,则可以在符号链接旁边或与符号链接目标相同的目录中找到公钥(此功能需要系统上提供 readlink 命令)。
  • 要禁用图形提示并始终在终端上输入密码,请使用 --nogui 选项。这允许例如从密码管理器复制粘贴长密码。
  • 如果您不想立即提示解锁密钥,而是等到需要它们时,请使用 --noask 选项。
注意
  • Keychain 能够以相同的方式管理 GPG 密钥。默认情况下,它仅尝试启动 ssh-agent,但您可以使用 --agents 选项修改此行为,例如 --agents ssh,gpg。请参阅 keychain(1)
  • 如果您在 Wayland 上,您可能需要按照 keychain issue 148 中的说明添加 --inherit any-once

x11-ssh-askpass

x11-ssh-askpass 软件包提供了一个图形对话框,用于在运行 X 会话时输入您的密码。x11-ssh-askpass 仅依赖于 libx11libxt 库,并且 x11-ssh-askpass 的外观是可定制的。虽然它可以由 ssh-add 程序调用,然后将您的解密密钥加载到 ssh-agent 中,但以下说明将配置 x11-ssh-askpass 以由上述 Keychain 脚本调用。

安装 keychainx11-ssh-askpass 软件包。

编辑您的 ~/.xinitrc 文件以包含以下行,如果需要,替换您的私钥的名称和位置。请务必将这些命令放在调用您的窗口管理器的行之前

~/.xinitrc
keychain ~/.ssh/id_ecdsa
[ -f ~/.keychain/$HOSTNAME-sh ] && . ~/.keychain/$HOSTNAME-sh 2>/dev/null
[ -f ~/.keychain/$HOSTNAME-sh-gpg ] && . ~/.keychain/$HOSTNAME-sh-gpg 2>/dev/null
...
exec openbox-session

在上面的示例中,第一行调用 keychain 并传递您的私钥的名称和位置。如果这不是第一次调用 keychain,则以下两行加载 $HOSTNAME-sh$HOSTNAME-sh-gpg 的内容(如果它们存在)。这些文件存储了先前 keychain 实例的环境变量。

使用 x11-ssh-askpass 调用 ssh-add

ssh-add 手册页指定,除了需要定义 DISPLAYWAYLAND_DISPLAY 变量外,您还需要将 SSH_ASKPASS 设置为您的 askpass 程序的名称(在本例中为 x11-ssh-askpass)。请记住,默认的 Arch Linux 安装将 x11-ssh-askpass 二进制文件放在 /usr/lib/ssh/ 中,这不会在大多数人的 PATH 中。这有点烦人,不仅在声明 SSH_ASKPASS 变量时,而且在主题化时也是如此。您必须在任何地方指定完整路径。通过符号链接可以同时解决这两个不便之处

$ ln -sv /usr/lib/ssh/x11-ssh-askpass ~/bin/ssh-askpass

这是假设 ~/bin 在您的 PATH 中。因此,现在在您的 .xinitrc 中,在调用您的窗口管理器之前,只需导出 SSH_ASKPASS 环境变量

$ export SSH_ASKPASS=ssh-askpass

并且您的 X 资源 将包含类似以下内容

ssh-askpass*background: #000000

这样做与 上述使用 ssh-agent 作为包装程序的方法 配合良好。您使用 ssh-agent startx 启动 X,然后将 ssh-add 添加到窗口管理器的启动程序列表中。

主题化

可以通过设置其关联的 X 资源来自定义 x11-ssh-askpass 对话框的外观。一些示例是在 https://github.com/sigmavirus24/x11-ssh-askpass 上的 .ad 文件。有关完整详细信息,请参阅 x11-ssh-askpass(1)

替代密码对话框

还有其他密码对话框程序可以代替 x11-ssh-askpass 使用。以下列表提供了一些替代解决方案。

pam_ssh

pam_ssh 项目旨在为 SSH 私钥提供 可插拔身份验证模块 (PAM)。此模块可以为您的 SSH 连接提供单点登录行为。登录时,可以输入您的 SSH 私钥密码短语来代替或补充您的传统系统密码。一旦您通过身份验证,pam_ssh 模块将生成 ssh-agent 以在会话期间存储您的解密私钥。

要在 tty 登录提示符下启用单点登录行为,请安装非官方的 pam_sshAUR 软件包。

注意: pam_ssh 2.0 现在要求在身份验证过程中使用的所有私钥都位于 ~/.ssh/login-keys.d/ 下。

创建一个指向您的私钥文件的符号链接,并将其放在 ~/.ssh/login-keys.d/ 中。将以下示例中的 id_rsa 替换为您自己的私钥文件的名称。

$ mkdir ~/.ssh/login-keys.d/
$ cd ~/.ssh/login-keys.d/
$ ln -s ../id_rsa

编辑 /etc/pam.d/login 配置文件以包含以下示例中以粗体突出显示文本。这些行出现的顺序很重要,可能会影响登录行为。

警告: 错误配置 PAM 可能会使系统处于所有用户都被锁定的状态。在进行任何更改之前,您应该了解 PAM 配置的工作原理以及访问 PAM 配置文件的备份方法,例如 Arch Live CD,以防您被锁定并且需要恢复任何更改。IBM developerWorks 上有一篇文章 解释了 PAM 配置的更多细节。
/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_ssh.so        try_first_pass
account    include      system-local-login
session    include      system-local-login
session    optional     pam_ssh.so

在上面的示例中,登录身份验证最初像往常一样进行,用户被提示输入其用户密码。添加到身份验证堆栈末尾的附加 auth 身份验证规则然后指示 pam_ssh 模块尝试解密在 ~/.ssh/login-keys.d 目录中找到的任何私钥。try_first_pass 选项传递给 pam_ssh 模块,指示它首先尝试使用先前输入的用户密码解密任何 SSH 私钥。如果用户的私钥密码短语和用户密码相同,则这应该会成功,并且用户不会被提示输入相同的密码两次。如果用户的私钥密码短语和用户密码不同,则 pam_ssh 模块将在用户密码输入后提示用户输入 SSH 密码短语。optional 控制值确保没有 SSH 私钥的用户仍然能够登录。通过这种方式,pam_ssh 的使用对于没有 SSH 私钥的用户将是透明的。

如果您使用另一种登录方式,例如 X11 显示管理器(如 SLiMXDM),并且您希望它提供类似的功能,则必须以类似的方式编辑其关联的 PAM 配置文件。提供 PAM 支持的软件包通常在 /etc/pam.d/ 目录中放置默认配置文件。

有关如何使用 pam_ssh 及其选项列表的更多详细信息,请参见 pam_ssh(8) 手册页。

使用不同的密码来解锁 SSH 密钥

如果您想根据您是使用密钥的密码短语还是(不同的!)登录密码来解锁 SSH 密钥,您可以修改 /etc/pam.d/system-auth

/etc/pam.d/system-auth
#%PAM-1.0

auth      [success=1 new_authtok_reqd=1 ignore=ignore default=ignore]  pam_unix.so     try_first_pass nullok
auth      required  pam_ssh.so      use_first_pass
auth      optional  pam_permit.so
auth      required  pam_env.so

account   required  pam_unix.so
account   optional  pam_permit.so
account   required  pam_time.so

password  required  pam_unix.so     try_first_pass nullok sha512 shadow
password  optional  pam_permit.so

session   required  pam_limits.so
session   required  pam_unix.so
session   optional  pam_permit.so
session   optional  pam_ssh.so

有关解释,请参阅 [7]

pam_ssh 的已知问题

pam_ssh 项目的工作不频繁,提供的文档也很稀疏。您应该意识到其一些在软件包本身中未提及的限制。

  • 版本 2.0 之前的 pam_ssh 版本不支持采用较新的 ECDSA(椭圆曲线)加密选项的 SSH 密钥。如果您使用的是早期版本的 pam_ssh,则必须使用 RSA 密钥。
  • pam_ssh 生成的 ssh-agent 进程不会在用户登录之间持久存在。如果您想在登录之间保持 GNU Screen 会话处于活动状态,您可能会注意到,当重新连接到您的 screen 会话时,它无法再与 ssh-agent 通信。这是因为 GNU Screen 环境及其子环境仍将引用在调用 GNU Screen 时存在的 ssh-agent 实例,但该实例随后在先前的注销中被杀死。Keychain 前端通过在登录之间保持 ssh-agent 进程处于活动状态来避免此问题。

pam_exec-ssh

作为 pam_ssh 的替代方案,您可以使用 pam_exec-ssh-gitAUR。它是一个使用 pam_exec 的 shell 脚本。有关配置的帮助,请参见 上游

GNOME Keyring

GNOME Keyring 工具可以充当 ssh-agent 的包装器,提供 GUI 和/或自动密钥解锁。有关更多详细信息,请参阅 GNOME Keyring#SSH 密钥

使用 Kwallet 存储 SSH 密钥

有关如何使用 kwallet 存储您的 SSH 密钥的说明,请参阅 KDE Wallet#使用 KDE Wallet 存储 ssh 密钥密码短语

KeePass2 与 KeeAgent 插件

KeeAgentKeePass 的插件,允许存储在 KeePass 数据库中的 SSH 密钥被其他程序用于 SSH 身份验证。

  • 支持 PuTTY 和 OpenSSH 私钥格式。
  • 在 Linux/Mac 上与原生 SSH 代理一起工作,在 Windows 上与 PuTTY 一起工作。

请参阅 KeePass#在 KeePass 中安装插件安装 keepass-plugin-keeagent 软件包。

此代理可以直接使用,通过匹配 KeeAgent 套接字:KeePass -> 工具 -> 选项 -> KeeAgent -> 代理模式套接字文件 -> %XDG_RUNTIME_DIR%/keeagent.socket- 和环境变量: export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR"'/keeagent.socket'

KeePassXC

KeePass 的分支 KeePassXC 可以充当现有 SSH 代理的客户端。存储在其数据库中的 SSH 密钥可以自动(或手动)添加到代理。它也与 KeeAgent 的数据库格式兼容。

故障排除

密钥被服务器忽略

  • 如果 SSH 服务器似乎忽略了您的密钥,请确保您已在所有相关文件上设置了正确的权限。
对于本地机器
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/key
对于远程机器
$ chmod 700 ~/.ssh
$ chmod 600 ~/.ssh/authorized_keys
对于远程机器,还要检查目标用户的 home 目录是否具有正确的权限(它必须不可被组和其他用户写入)
$ chmod go-w ~target_user
  • 如果这不能解决问题,您可以尝试临时将 StrictModes 设置为 no/etc/ssh/sshd_config 中。如果使用 StrictModes off 身份验证成功,则可能是文件权限问题仍然存在。
  • 确保 ~/.ssh/authorized_keys 中的密钥输入正确,并且仅使用单行。
  • 确保远程机器支持您正在使用的密钥类型:某些服务器不支持 ECDSA 密钥,请尝试改用 RSA 密钥,请参阅 #生成 SSH 密钥对
  • 您可能想要使用调试模式并在连接时监视输出
# /usr/bin/sshd -d
  • 如果您为密钥起了另一个名称,例如 id_rsa_server,则需要使用 -i 选项连接
$ ssh -i id_rsa_server user@server

agent refused operation (代理拒绝操作)

如果您的私钥需要密码(或者,例如,您有一个带有 PIN 码的硬件密钥),但 ssh-agent 没有提供密码,则 ssh 将失败

sign_and_send_pubkey: signing failed for ECDSA-SK user@host from agent: agent refused operation

一个可能的原因是 ssh-agent 无法提示输入密码。确保 ssh-agent 可以访问显示服务器(通过 DISPLAY 环境变量)或 TTY。对于某些图形环境,您可能只需要安装 x11-ssh-askpass,对于其他设置,也请遵循 #x11-ssh-askpass 说明。

如果使用硬件身份验证器,则另一个原因可能是密钥故障或未插拔。

当前存在一个公开的 bug,当使用使用 -O verify-required 选项创建的身份验证器密钥(如 ED25519-sk 和 ECDSA-SK)时,会触发“agent refused operation”错误。为避免此问题,请为 ssh 命令使用 -o IdentityAgent=none -o IdentitiesOnly=yes 选项,或将其添加到您的 ssh_config 文件中以用于相关主机

Host myserver.tld
    IdentityAgent none
    IdentitiesOnly yes

另请参阅