OpenSSH
客户端配置文件可以按用户或系统范围设置,其中用户配置文件的优先级高于系统配置文件,运行时的命令行参数优先于两者。在这些配置文件中,每行只允许一个参数。语法是参数名后跟其值或值列表。空行和以井号(#)开头的行会被忽略。可以使用等号(=)代替空格,连接参数名和对应的值。值是区分大小写的,但参数名不区分大小写。为键文件分配的第一个值会被使用。
无论是哪种类型的文件,最好的做法是阅读涉及的实际系统上的相关手册页面,特别是因为它们与实际使用的特定版本相匹配。
系统范围的客户端配置文件
系统范围的客户端文件设置了该系统上所有OpenSSH客户端的默认配置。用户本地的配置文件通常可以覆盖这些默认设置。两者都可以在运行时通过指定各种选项或参数来覆盖。优先级顺序如下:
- 运行时的命令行参数
- 用户的本地配置
- 系统范围的配置
获取到的第一个值会被使用。用户的配置文件和系统范围的配置文件也可以使用Include指令指向其他配置文件,这从OpenSSH 7.3开始支持。Include指令可以在配置文件中的任何位置指定,甚至可以在Match或Host块内。需要谨慎处理配置文件的嵌套。
/etc/ssh/ssh_config
该文件定义了系统上所有用户客户端实用程序的默认设置,必须对所有用户可读。配置选项在ssh_config(5)中有详细说明。
以下是一个连接到arc.example.org的快捷配置示例:
Host arc
Port 2022
HostName arc.example.org
User fred
IdentityFile ~/.ssh/id_rsa_arc
使用这个配置后,只需输入ssh arc
,其余的信息会自动填充。
/etc/ssh/ssh_known_hosts
该文件包含系统范围的已知主机密钥列表,用于验证远程主机的身份,从而防止伪装或窃听。此文件应由系统管理员准备,包含所有必要主机的公钥,且应对所有用户可读。
有关此文件格式的更多信息,请参见~/.ssh/known_hosts
,或查看sshd(8)手册中的详细说明。
/etc/ssh/sshrc
该文件位于服务器端,当用户登录时,ssh(1)会在启动用户的shell或指定程序之前执行该文件中的程序。该文件不是以root身份运行的,而是以登录用户的身份运行。更多信息请参见sshd(8)手册中的“SSHRC”部分。如果该文件向stdout发送任何内容,可能会干扰SFTP会话等。因此,如果有任何输出,应将其发送到stderr,或记录到日志文件中。
用户特定的客户端配置文件
用户可以覆盖系统范围的默认设置,选择自己的默认配置。对于那些需要反复更改的情况,建议将更改添加到用户的本地配置中。
客户端文件
这些文件位于客户端机器上。
~/.ssh/config
这是用户的配置文件,在适用的情况下,它会覆盖全局客户端配置文件/etc/ssh/ssh_config
中的设置。配置选项在ssh_config(5)中有详细说明。
该文件必须对其他用户不可访问,设置严格的权限:用户可以读写,其他人不可访问。如果该文件属于某个组,且该组只有该用户是成员,则该文件可以被组写。
本地覆盖客户端默认值
该文件通常命名为~/.ssh/config
,但可以使用-F
选项在运行时指定其他配置文件。一般选项通常会设置在所有主机匹配的地方,最好将它们放在配置文件的最后面。第一个匹配项优先,因此更具体的定义应放在前面,而更一般的覆盖设置应放在文件的末尾。
Host server1
ServerAliveInterval 200
HostName 203.0.113.76
Host *
ExitOnForwardFailure yes
Protocol 2
ServerAliveInterval 400
运行时传入的选项将覆盖配置文件中的设置。不过,并非所有选项都可以被用户设置或覆盖,无法设置或覆盖的选项将被忽略。
~/.ssh/known_hosts
该文件属于用户帐户,包含已知的远程主机密钥。这些密钥通常在首次连接时从主机中获取,但也可以手动添加。与全局文件/etc/ssh/ssh_known_hosts
中的密钥一样,这些密钥用于验证远程主机的身份,从而防止伪装或中间人攻击。在每次后续连接时,密钥将与远程服务器提供的密钥进行比较。如果匹配,连接将继续。如果匹配失败,ssh(1)将失败并显示错误消息。如果没有列出该远程主机的密钥,将显示该密钥的指纹,并且会提供自动将密钥添加到文件的选项。该文件可以手动创建和编辑,但如果该文件不存在,ssh(1)将在首次连接远程主机时自动创建它。
~/.ssh/known_hosts
文件可以使用哈希或明文主机名。即使是哈希的名称,使用ssh-keygen(1)
的-F
选项也可以进行搜索。
$ ssh-keygen -F server3.example.com
默认情况下,搜索的文件是~/.ssh/known_hosts
,如果找到该密钥,则会打印出来。也可以使用-f
选项搜索其他文件。如果需要从文件中删除某个密钥,-R
选项与按主机搜索并删除密钥的方式类似,即使主机名是哈希的也能删除。
$ ssh-keygen -R server4.example.com -f ~/.ssh/known_hosts
删除密钥后,该密钥将附加到~/.ssh/known_hosts.old
文件中,以防以后需要它。有关这些known_host
文件的格式,请参见sshd(8)手册。
如果使用非默认文件,通过-F
或-R
选项时,必须使用-f
指定文件名(包括路径)。如果使用默认文件,则-f
选项是可选的。
手动添加公钥到~/.ssh/known_hosts
手动将公钥添加到known_hosts
文件是将每个密钥添加为一行。获取密钥的方式并不重要,只要密钥完整有效,并且能够确保是正确的公钥,而非伪造的。可以使用ssh-keyscan(1)
获取密钥,ssh-keygen(1)
可以用来显示指纹进行验证。有关验证方法,请参阅公钥认证的示例章节。系统范围的相应文件是/etc/ssh/ssh_known_hosts
。
关于known_hosts
文件的内容
known_hosts
文件用于验证其他系统的身份。ssh(1)可以自动将密钥添加到用户的文件中,但也可以手动添加。该文件包含用户连接过的所有主机的公钥,也可以包含用户计划登录的主机的公钥,即使它们尚未在系统范围的已知主机密钥列表中。通常在首次连接主机时,ssh(1)会将远程主机的公钥添加到用户的known_hosts
文件中,但此行为可以调整。
文件格式是每个公钥或证书占一行。每行包含主机名、位数、指数和模数。行的开头是主机名或表示主机名的哈希值。行末可以有一个可选的注释。如果使用SSH证书而不是SSH密钥,还可以在行前添加一个可选的标记以指示证书颁发机构。这些字段之间用空格分隔。如果主机有多个名称,或者同一密钥在多个机器上使用,则主机名字段可以使用逗号分隔的主机名列表。
服务器端客户端文件
这些客户端文件存储在服务器上。默认情况下,它们保存在用户的目录中,但如果需要,服务器可以配置为在其他位置查找这些文件。
~/.ssh/authorized_keys
authorized_keys
是一个每行一个公钥的注册表,用于存储此帐户可用于登录的公钥(ECDSA、RSA 和 ED25519)。该文件的内容不是非常敏感,但推荐的权限是用户可读/写,且其他用户无法访问。和往常一样,整个密钥,包括选项和注释,必须在同一行中,不可分割。
例如:
ssh-rsa AAAAB3NzaC1yc2EAAA...41Ev521Ei2hvz7S2QNr1zAiVaOFy5Lwc8Lo+Jk=
以哈希符号(#)开头的行会被忽略,可以用于注释。空格分隔密钥的各个字段,字段顺序通常是可选的登录选项、密钥类型(通常是 ssh-rsa 或更好的如 ecdsa-sha2-nistp256)、以 base64 编码的密钥本身,以及可选的注释。
如果密钥后面跟有注释,注释不需要用引号括起来,它对密钥的功能没有任何影响。例如:
ssh-rsa AAAAB3NzaC1yc2EAAA...zAiVaOFy5Lwc8Lo+Jk= Fred @ Project FOOBAR
密钥可以前面加上逗号分隔的选项列表,以控制登录成功后发生的事情。例如,以下第一个密钥强制会自动启动 tinyfugue
会话,第二个则强制设置 PATH
环境变量:
command="/usr/bin/tinyfugue" ssh-rsa AAAAB3NzaC1yc2EAAA...OFy5Lwc8Lo+Jk=
environment="PATH=/bin:/usr/bin/:/opt/gtm/bin" ssh-rsa AAAAB3N...4Y2t1j=
authorized_keys
文件的格式在 sshd(8)
手册页中有详细描述。过时的密钥应从文件中删除。服务器可以指定多个位置来存放 authorized_keys
文件,详情请参见后续部分“服务器端客户端密钥登录选项”。
~/.ssh/authorized_principals
默认情况下,文件 ~/.ssh/authorized_principals
不存在。如果在 sshd_config(5)
中指定了此文件,它包含一个可以用来代替用户名的名称列表,用于授权证书。此选项对于角色账户、分离的账户命名空间以及证书中的 "user@realm" 样式命名策略非常有用。也可以在 authorized_keys
文件中指定主机。
~/.ssh/environment
如果服务器配置为在登录过程中接受用户提供的自动更改环境变量,那么这些更改可以在此文件中设置。
如果服务器、环境文件和授权密钥都尝试更改同一变量,则环境文件中的内容优先于密钥中的内容。任意一个会覆盖通过 ssh(1)
使用 SendEnv
传递的环境变量。
存储在 authorized_keys
中的认证密钥也可以用来设置变量。有关更多信息,请参见 sshd_config(5)
中的 AcceptEnv
和 PermitUserEnvironment
指令。
~/.ssh/rc
这是一个脚本,会在用户的 shell 或命令启动之前由 sh(1)
执行。如果使用了 ForceCommand
,则不会运行此脚本。脚本在读取环境变量之后运行。如果用户的 rc
脚本存在,则不会执行对应的全局文件 /etc/ssh/sshrc
。
本地账户公钥/私钥对
用户可能会在文件系统中存储多种类型的密钥,如 ECDSA、Ed25519 和 RSA 密钥。从版本 8.2 开始,还支持 ECDSA-SK 和 Ed25519-SK 这两种新的密钥类型,以及与其对应的证书类型,这些密钥绑定到 FIDO/U2F 令牌。虽然各个账户可以在任何目录中维护自己的密钥或证书列表来进行身份验证或验证远程主机的身份,但最常见的存储位置是在 ~/.ssh/
目录中。密钥的命名约定仅为约定,但仍然建议遵循。公钥通常与私钥同名,但会在文件名后加上 .pub
后缀。如果公钥和私钥的名字不匹配,可能会出现问题。如果有多个密钥对,可以使用 ssh-keygen(1)
的 -f
选项生成有用的名称,并使用 -C
选项将相关注释嵌入到密钥对中。
人、程序和脚本可以使用系统上存储的私钥进行身份验证,甚至可以使用从智能卡中获取的私钥,只要相应的公钥存储在远程系统的 authorized_keys
文件中。authorized_keys
文件本身不是特别敏感,但推荐的权限是用户可读/写,并且其他用户不可访问。私钥则非常敏感,应该不能被其他账户读取或看到。它们永远不应该离开客户端,当然也不应该放到服务器上。
密钥可以前面加上逗号分隔的选项列表。整个密钥必须在同一行中,不可分割,不允许有空格,除非在双引号内。密钥后面的任何文本都被视为注释。
authorized_keys
文件是一个每行一个公钥的注册表,公钥类型包括 RSA、Ed25519、ECDSA、Ed25519-SK 和 ECDSA-SK,这些密钥可以用于登录到特定账户。请参见上面关于 authorized_keys
文件的部分以获得更多信息。
DSA 密钥已经被视为过时。DSA 密钥不再被认为安全,应当用更好的密钥来替代。
每个账户的基于主机的认证配置
也可以使用 ~/.shosts
、~/.rhosts
、~/.ssh/environment
和 ~/.ssh/rc
文件进行基于主机的认证配置。
客户端公钥
这些是公钥的默认名称。实际的文件名可以是任何名字,位置也可以是任何目录。
例如:
~/.ssh/id_ecdsa.pub ~/.ssh/id_ed25519.pub ~/.ssh/id_rsa.pub ~/.ssh/id_ecdsa-sk.pub ~/.ssh/id_ed25519-sk.pub ~/.ssh/id_ecdsa-sk_rk.pub ~/.ssh/id_ed25519-sk_rk.pub
同样,给密钥取一个更相关的名称是一个好主意。*-sk.pub
是与硬件安全令牌绑定的密钥,而 *-sk_rk.pub
是从硬件安全令牌中存储的居民密钥生成的密钥。
公钥主要用于远程服务器上的基于密钥的认证。公钥不是敏感的,可以被任何人读取,与私钥不同,但也没有必要让它们成为公开可见的。公钥可以从私钥中重新生成,如果丢失了公钥。不过,和私钥不同的是,一旦私钥丢失,就不能重新生成新的私钥。
客户端私钥
像客户端的公钥一样,私钥的实际文件名可以是任何名字,位置也可以是任何目录。以下是客户端私钥的默认名称:
~/.ssh/id_ecdsa ~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_ecdsa-sk ~/.ssh/id_ed25519-sk ~/.ssh/id_ecdsa-sk_rk ~/.ssh/id_ed25519-sk_rk
私钥始终被视为敏感数据,只能由用户读取,其他人无法访问。也就是说,它们应该使用 0600 权限。它们所在的目录也应该使用 0700 或 0500 权限。如果私钥文件对其他用户可访问,ssh(1)
将忽略它。
生成密钥时,可以指定一个密码短语,用于使用 AES128 加密文件的敏感部分。直到版本 5.3,密码短语使用 3DES 加密。旧的使用 3DES 加密的密钥在修改时会使用 AES128。
存储在硬件令牌中的私钥可以提取,并自动用于生成其对应的公钥,使用 ssh-keygen(1)
的 -K
选项。此类密钥默认会命名为 id_ecdsa-sk_rk
或 id_ed25519-sk_rk
,具体取决于密钥类型,尽管在提取后可以更改文件名。可以在从令牌提取到文件时为私钥指定密码短语。
虽然公钥可以从私钥生成,但丢失私钥后无法从公钥生成新的私钥。如果忘记了当前密码短语,则无法重新设置新的密码短语。与公钥不同,一旦私钥
丢失,就无法恢复,必须重新生成并部署一对新的密钥。
过时文件
这些文件可能会在非常旧或过时的系统中出现,但在现代系统中通常不会见到。
~/.shosts
~/.shosts
是从 rsh 继承的一个过时文件,包含本地的信任主机-用户对列表,允许这些主机用户进行登录。匹配到条目的登录请求会被允许访问。
另见全局信任主机-用户对列表:/etc/hosts.equiv
rhosts
可以作为主机认证的一部分使用。但不建议使用 rhosts
进行认证,因为它容易导致 .rhosts
文件配置错误。
过时的 DSA 密钥
~/.ssh/id_dsa
和 ~/.ssh/id_dsa.pub
过时的 DSA 密钥可能会以 id_dsa
和 id_dsa.pub
的形式出现,但无论名称如何,都应该追踪其使用情况。自 OpenSSH 7.0 起,DSA 密钥在服务器和客户端都已被弃用。如果发现了 DSA 密钥,应该将其删除并替换为更好的密钥类型。
过时的 SSH1 协议密钥
~/.ssh/identity
和 ~/.ssh/identity.pub
identity
和 identity.pub
文件是为 SSH 协议版本 1 设计的,因此已被弃用。如果发现这些文件,应调查其是否仍在使用,并找出具体原因。一旦不再需要使用这些文件,就应该删除它们并替换为更新的密钥类型。
客户端选项与配置指令映射
许多 SSH 客户端的运行时选项都有对应的配置指令,反之亦然。以下是一个简要概述,但不能替代详细了解相关手册页,ssh(1)
和 ssh_config(5)
是权威且最新的资源。
OpenSSH 客户端选项与配置指令对照表
指令 | 选项 | 描述 |
---|---|---|
AddressFamily | -4 / -6 | 限制连接仅使用 IPv4 或 IPv6。 |
ForwardAgent | -A / -a | 转发或阻止来自认证代理的转发。 |
BindInterface | -B | 将出站连接绑定到此网络接口。 |
BindAddress | -b | 将出站连接绑定到此网络地址。 |
Compression | -C | 指定是否使用 gzip(1) 压缩数据。 |
Ciphers | -c | 指定使用哪种加密算法。 |
DynamicForward | -D | 指定一个本地端口进行转发,比如用于 SOCKS5。 |
EscapeChar | -e | 为 PTY 会话指定一个转义字符。 |
ForkAfterAuthentication | -f | 在命令执行之前将客户端进程放入后台。 |
GatewayPorts | -g | 是否允许其他主机连接到本地转发的端口。 |
PKCS11Provider | -I | 指定 PKCS#11 库的路径。 |
IdentityFile | -i | 指定用于认证的特定证书或私钥。 |
ProxyJump | -J | 通过此主机或主机列表先连接到目标主机。 |
GSSAPIAuthentication | -K / -k | 启用或禁用 GSSAPI 认证。 |
LocalForward | -L | 指定将要转发到指定远程系统的本地端口或套接字。 |
User | -l | 指定要尝试的远程系统帐户。 |
ControlMaster | -M | 允许在单一 TCP 连接上进行 SSH 会话复用。 |
MACs | -m | 指定要尝试的消息认证码 (MAC) 算法。 |
SessionType | -N / -s | 调用指定的子系统,或者禁止执行任何命令。 |
StdinNull | -n | 阻止从 stdin 读取数据。 |
Tag | -P | 在 Match 中使用的标签。 |
Port | -p | 连接到远程系统的此端口。 |
LogLevel | -q / -v | 调整客户端日志消息的详细程度。 |
RemoteForward | -R | 指定将要转发到指定本地系统的远程端口或套接字。 |
ControlPath | -S | 指定用于此连接的控制套接字。 |
RequestTTY | -T / -t | 禁止或请求为会话分配伪 TTY。 |
ForwardX11 | -X / -x | 启用或禁止 X11 转发。 |
自版本 8.7 起,-f
、-N
和 -n
选项也在 ssh_config(5)
中有对应的客户端配置指令。
服务器端客户端密钥登录选项
在本地用户的授权密钥文件中使用的登录选项可能会被服务器的设置覆盖或阻止。但在这一限制下,以下选项可以使用。
cert-authority
指定列出的密钥为认证机构 (CA),可用于验证用户认证的签名证书。证书可以编码类似于密钥选项的访问限制。如果同时存在证书限制和密钥限制,则应用二者的最严格的并集。
command="program"
指定当密钥用于认证时执行的程序及其选项。这是限制密钥仅用于单一特定操作(如远程备份)的好方法。但即使如此,TCP 和 X11 转发仍然被允许,除非显式禁用。
该程序在客户端请求时会在 PTY 上运行,否则默认在没有 TTY 的情况下运行。默认的无 TTY 运行提供一个 8 位清洁通道。如果默认设置已更改,可以指定 no-pty
来获得 8 位清洁通道。如果不允许任何程序运行,可以使用空字符串 ""
来阻止任何程序执行。
environment="NAME=value"
当此密钥用于登录时,设置环境变量的值。如果已存在该变量的默认值,则会被覆盖。可以重复此选项,最多设置 1024 个不同的变量。重复时,首先匹配的值会生效。此选项仅在 SSH 服务器配置中启用了 PermitUserEnvironment
选项时才允许。默认情况下,它是禁用的。
expiry-time="timespec"
设置密钥过期的日期或时间,格式为 YYYYMMDD
或 YYYYMMDDHHMM[SS]
。过期后,密钥将不再允许认证,否则该密钥将被认为是永久有效的。
from="pattern-list"
除了密钥外,还需要远程主机的规范名称或 IP 地址。地址和主机名可以使用逗号分隔的模式列表列出,详细信息请参见 ssh_config(5)
中的 PATTERNS,或者使用 CIDR 地址/掩码长度表示法。
no-agent-forwarding
/ agent-forwarding
禁用或允许在认证时转发代理密钥。此选项可以覆盖 restrict
选项,即使它原本被禁用。
no-port-forwarding
/ port-forwarding
禁止 TCP 转发,客户端的任何端口转发请求将在使用该密钥时返回错误。也可以通过 permitopen
选项覆盖此限制,允许端口转发。
restrict
禁用所有选项,如 TTY 分配、端口转发、代理转发、用户 RC 和 X11 转发。然后可以逐一显式允许特定选项。
管理密钥
在管理密钥时,应该采取一些基本的常识措施来避免问题。最有益的做法是为密钥文件使用合理的名称并嵌入注释。使用 ssh-keygen(1)
的 -f
选项可以设置自定义名称,-C
选项可以将注释嵌入公钥和私钥中。
此外,管理密钥的三大基本原则包括:
- 使用强密码短语。如果需要自动登录,则应首先将密钥加载到代理中,并从中使用。
- 密钥应存储在受保护的位置。尤其是私钥,应限制只能由所有者读取,且应存储在仅所有者可访问的目录中。
- 删除过时和未使用的密钥。特别是没有已知有效用途的密钥,应从服务器中删除,防止积累。
遵循最小特权原则可以减少事故或滥用的机会。