22 使用 OpenSSH 保护网络操作 #
OpenSSH 是 SUSE Linux Enterprise Desktop 随附的 SSH(安全外壳)实现,用于保护远程管理、文件传输等网络操作,以及为不安全的协议构建隧道。SSH 加密两台主机之间的所有流量(包括身份验证),以防范窃听和连接劫持。本章介绍基本操作以及主机密钥轮换和证书身份验证,这些操作对于管理大型 SSH 部署非常有用。
22.1 OpenSSH 概览 #
SSH 是一种网络协议,可为网络中计算机之间的通讯或网络中计算机与网络外部的系统之间的通讯提供端到端保护。如果您有远程计算机的登录名和正确的身份验证方法,就能与任何其他计算机建立 SSH 会话。
SSH 是一种客户端-服务器协议。任何运行 sshd
守护程序的主机都可以接受来自任何其他主机的 SSH 连接。每个运行 sshd
的主机都可以有自身的自定义配置,例如限制哪些用户可以进行访问,以及允许哪些身份验证方法。
身份验证和加密由加密密钥对提供。每个密钥对都有一个公共密钥和一个私用密钥。公共密钥用于加密,私用密钥用于解密。公共密钥可任意共享,而私用密钥必须受到保护且不可共享。当私用密钥被透露时,任何拥有它的人都可以伪装成原始密钥所有者。
SSH 可提供可靠的保护,因为服务器和客户端必须互相进行身份验证。当客户端首次尝试打开 SSH 会话时,服务器会提供其公共主机密钥。如果客户端已拥有此密钥的副本(存储在客户端计算机上的 ~/.ssh/known_hosts
中),则客户端知道服务器可信。如果客户端没有相应的主机密钥,则系统会询问它是否应信任服务器:
The authenticity of host '192.168.22.219 (192.168.22.219)' can't be established. ECDSA key fingerprint is SHA256:yXf6pjV26N0fegvEYIt3HgG95s3Q1X6WYRhtHLF99pUo. Are you sure you want to continue connecting (yes/no/[fingerprint])?
用户可以键入 yes
或 no
,或者粘贴其主机密钥指纹的副本进行比较。
将主机密钥指纹副本分发给用户可使他们能够校验是否收到了正确的主机密钥。当他们粘贴主机密钥指纹的副本时,ssh
将比较指纹,并在指纹匹配时接受提供的主机密钥。这可以确保匹配精确度高于视觉比较。
您不能依赖用户使用正确的校验方法。如果指纹不匹配,用户仍可以键入 yes
或者复制消息中的指纹,并完成连接。另一种更可靠的方法是使用证书身份验证,它可以提供全局身份验证机制,并且不需要用户完全按要求操作(请参见第 22.8 节 “OpenSSH 证书身份验证”)。
如果主机的公共密钥已更改,则会拒绝连接并出现严肃的警告:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that a host key has just been changed. The fingerprint for the ECDSA key sent by the remote host is SHA256:keNu/rJFWmpQu9B0SjIuo8NLjbeDY/x3Tktpl7oDJqo. Please contact your system administrator. Add correct host key in /home/geeko/.ssh/known_hosts to get rid of this message. Offending ECDSA key in /home/geeko/.ssh/known_hosts:210 You can use following command to remove the offending key: ssh-keygen -R 192.168.121.219 -f /home/geeko/.ssh/known_hosts ECDSA host key for 192.168.121.219 has changed and you have requested strict checking. Host key verification failed.
补救措施是使用警告中给出的命令从 ~/.ssh/known_hosts
中删除有问题的密钥,然后重新连接并接受新的主机密钥。
openssh 软件包会安装服务器、客户端、文件传输命令和一些实用程序。
OpenSSH 支持多种不同类型的身份验证:
- 口令身份验证
使用远程计算机上的任何系统登录名和口令。这是最简单、最灵活的身份验证方法,因为您可以在任何位置的任何计算机上打开 SSH 会话。但它也是最不安全的方法,因为这很容易遭到口令破解和按键记录攻击。
- 公共密钥身份验证
使用您的个人 SSH 密钥而不是登录名和口令进行身份验证。这种方法不如口令身份验证那么灵活,因为您只能从拥有您的私用身份密钥的计算机打开 SSH 会话。但此方法要安全得多,因为它不容易遭到口令破解或按键记录攻击;攻击者必须拥有您的私用密钥并知道其通行口令。
请参见第 22.9 节 “使用 gnome-keyring 自动进行公共密钥登录”了解如何使用
gnome-keyring
在 GNOME 会话中自动进行公共密钥身份验证。请参见第 22.10 节 “使用 ssh-agent 自动进行公共密钥登录”了解如何使用
ssh-agent
在控制台会话中自动进行公共密钥身份验证。- 无通行口令公共密钥身份验证
将公共密钥与没有通行口令的私用密钥搭配使用进行身份验证。这对于脚本和 cron 作业等自动化服务很有用。您必须保护私用密钥,因为获取其访问权限的任何人都可以轻松伪装成密钥所有者。
- 证书身份验证
OpenSSH 支持证书身份验证,可以简化密钥管理、增强身份验证和实现大规模 SSH 部署。
默认情况下,SUSE Linux Enterprise Desktop 会安装可提供以下命令的 OpenSSH 软件包:
ssh
用来与远程主机发起 SSH 连接的客户端命令。
scp
从/向远程主机安全复制文件。
sftp
在客户端与 SFTP 服务器之间安全传输文件。(SFTP 协议 (SSH FTP) 与 FTPS 或 FTPES(基于 SSL/TLS 的 FTP)无关,而是独立编写的。)
ssh-add
将私用密钥身份添加到身份验证代理
ssh-agent
。ssh-agent
管理用户的私用身份密钥及其通行口令,以进行公共密钥身份验证。
ssh-agent
将通行口令保存在内存中,并会根据需要应用通行口令,这样用户就不必重新键入通行口令进行身份验证。ssh-copy-id
将公共密钥安全地传输到远程主机,以设置公共密钥身份验证。
22.2 服务器强化 #
OpenSSH 随附一个可用的默认服务器配置,但您还可以采取其他措施来保护服务器。
当您对任何 SSH 服务器进行更改时,可以对计算机进行物理访问,或者将活动的根 SSH 会话保持打开状态,直到您测试了更改并且一切正常。然后,如果出现问题,您可以还原或纠正更改。
默认服务器配置文件 /etc/ssh/sshd_config
包含默认配置,所有默认值已注释掉。您可以输入自己不带注释的配置项目来覆盖任何默认项目,例如,以下示例会设置不同的侦听端口,并指定多宿主主机上的 IPv4 侦听地址:
#Port 22 Port 2022 #ListenAddress 0.0.0.0 ListenAddress 192.168.10.100
使用非标准侦听端口时,请先检查 /etc/services
文件中是否存在未使用的端口。选择大于 1024 的任何未使用端口。然后在 /etc/services
中记录您正在使用的端口。
最佳实践是禁止 root 登录名。改用非特权用户登录到远程计算机,然后使用 sudo
以 root 身份运行命令。如果您确实想要允许使用 root 登录名,以下服务器配置示例演示了如何使用 PermitRootLogin prohibit-password
和 PasswordAuthentication
选项将服务器配置为仅接受 root 用户的公共密钥身份验证(第 22.6 节 “公共密钥身份验证”)。
/etc/ssh/sshd_config
的以下设置可以增强访问控制:
# Check if the file modes and ownership of the user’s files and # home directory are correct before allowing them to login StrictModes yes # If your machine has more than one IP address, define which address or # addresses it listens on ListenAddress 192.168.10.100 # Allow only members of the listed groups to log in AllowGroups ldapadmins backupadmins # Or, deny certain groups. If you use both, DenyGroups is read first DenyGroups users # Allow or deny certain users. If you use both, DenyUsers is read first AllowUsers user1 user2@example.com user3 DenyUsers user4 user5@192.168.10.10 # Allow root logins only with public key authentication PermitRootLogin prohibit-password # Disable password authentication and allow only public key authentication # for all users PasswordAuthentication no # Length of time the server waits for a user to log in and complete the # connection. The default is 120 seconds: LoginGraceTime 60 # Limit the number of failed connection attempts. The default is 6 MaxAuthTries 4
更改 /etc/ssh/sshd_config
后,运行语法检查程序:
>
sudo
sshd -t
语法检查程序只会检查语法是否正确,而不会查找配置错误。完成后,重载配置:
>
sudo
systemctl reload sshd.service
检查服务器关键目录的权限是否正确。
/etc/ssh
应采用 0755/drwxr-xr-x 模式,由 root:root 拥有。
私用密钥应该是 0600/-rw--------,由 root:root 拥有。
公共密钥应该是 0644/-rw-r--r--,由 root:root 拥有。
22.3 口令身份验证 #
使用口令身份验证时,只需获得远程计算机上用户的登录名和口令,在远程计算机上设置并运行 sshd
即可。不需要任何个人 SSH 密钥。在以下示例中,用户 suzanne 打开与主机 sun 的 SSH 会话:
>
ssh suzanne@sun
系统将提示 suzanne 输入远程口令。键入 exit
并按 Enter 关闭 SSH 会话。
如果两台计算机上的用户名相同,您就可以省略用户名,因为使用 ssh HOST_NAME
就已足够。成功完成身份验证后,可以通过命令行执行操作,或使用交互式应用程序(例如文本模式的 YaST)。
您还可以使用 ssh USER_NAME HOST COMMAND
语法在远程系统上运行非交互式命令(登录,运行命令,然后所有会话通过一条命令关闭)。必须正确地将 COMMAND 括在引号中。可以像在本地外壳中一样串联多个命令:
>
ssh suzanne@sun "df -h && du -sh /home"
>
ssh suzanne@sun "sudo nano /etc/ssh/sshd_config"
在远程计算机上运行 sudo
时,系统会提示您输入 sudo
口令。
22.4 管理用户和主机加密密钥 #
有多种密钥类型可供选择:DSA、RSA、ECDSA、ECDSA-SK、Ed25519 和 Ed25519-SK。DSA 在多年前已弃用,并且在 OpenSSH 7.0 中已禁用,请不要使用它。RSA 是最通用的类型,因为它问世较早,且使用较为广泛。(从 OpenSSH 8.2 开始,不再可以使用 RSA 作为主机密钥类型。请使用 ECDSA 或 Ed25519 作为主机密钥类型。)
Ed25519 和 ECDSA 更安全且更快。Ed25519 被认为是安全系数最高的密钥类型。如果您必须支持那些不支持 Ed25519 或 ECDSA 的旧客户端,请用所有三种格式创建主机密钥。
某些早期的 SSH 客户端不支持 ECDSA 和 ED25519。ECDSA 和 ED25519 已在 2014 年随 OpenSSH 6.5 一起发布。使安全服务保持更新非常重要,如果可能的话,请不要允许使用不安全的早期客户端。
SSH 密钥可以起到两项作用:向客户端验证服务器的身份,以及向服务器验证客户端的身份(请参见第 22.6 节 “公共密钥身份验证”)。服务器主机密钥存储在 /etc/ssh
中。用户的个人密钥存储在 /home/user/.ssh
中。
当用户创建新的 SSH 密钥时,会创建 /home/user/.ssh
。
主机密钥不能有通行口令。
在大多数情况下,用户私用密钥应具有强通行口令。
22.4.1 创建用户 SSH 密钥对 #
以下过程说明如何创建用户 OpenSSH 加密密钥。
要使用默认参数(RSA,3072 位)生成用户密钥对,请使用不带任何选项的
ssh-keygen
命令。使用强通行口令保护私用密钥:>
ssh-keygen
Generating public/private rsa key pair. Enter file in which to save the key (/home/tux/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in id_rsa Your public key has been saved in id_rsa.pub The key fingerprint is: SHA256:z0uJIuc7Doy07bFTe1ppZHLVrkD/bWWlBAF/PcHjblU user@host2 The key's randomart image is: +---[RSA 3072]----+ | ..o... | | o . +E| | . . o +.=| | . o . o o+| | . . S . . o +| | . = .= * + . = | | o *.o.= * . + | | ..Bo+.. . . | | oo== . | +----[SHA256]-----+创建一个位长度较长的 RSA 密钥对:
>
ssh-keygen -b 4096
OpenSSH RSA 密钥最多可以包含 16,384 位。但是,较长的位长度不一定更符合需求。有关详细信息,请参见 GnuPG 常见问题网页:https://www.gnupg.org/faq/gnupg-faq.html#no_default_of_rsa4096。
您可以创建任意数量的用户密钥用于访问不同的服务器。每个密钥对的名称必须唯一,可以选择性地为其提供注释。这些信息可帮助您记住每个密钥对的用途。使用自定义名称和注释创建 RSA 密钥对:
>
ssh-keygen -f backup-server-key -C "infrastructure backup server"
使用自定义名称和注释创建 Ed25519 密钥对:
>
ssh-keygen -t ed25519 -f ldap-server-key -C "Internal LDAP server"
Ed25519 密钥固定为 256 位,其加密强度相当于 RSA 4096。
22.4.2 创建 SSH 服务器主机密钥 #
主机密钥的管理方式略有不同。主机密钥不能有通行口令,密钥对存储在 /etc/ssh
中。在安装 OpenSSH 时,它会自动生成一组主机密钥,如以下示例所示:
>
ls -l /etc/ssh
total 608 -rw------- 1 root root 577834 2021-05-06 04:48 moduli -rw-r--r-- 1 root root 2403 2021-05-06 04:48 ssh_config -rw-r----- 1 root root 3420 2021-05-06 04:48 sshd_config -rw------- 1 root root 1381 2022-02-10 06:55 ssh_host_dsa_key -rw-r--r-- 1 root root 604 2022-02-10 06:55 ssh_host_dsa_key.pub -rw------- 1 root root 505 2022-02-10 06:55 ssh_host_ecdsa_key -rw-r--r-- 1 root root 176 2022-02-10 06:55 ssh_host_ecdsa_key.pub -rw------- 1 root root 411 2022-02-10 06:55 ssh_host_ed25519_key -rw-r--r-- 1 root root 96 2022-02-10 06:55 ssh_host_ed25519_key.pub -rw------- 1 root root 2602 2022-02-10 06:55 ssh_host_rsa_key -rw-r--r-- 1 root root 568 2022-02-10 06:55 ssh_host_rsa_key.pub
ssh-keygen
有一个特殊选项 -A
,该选项用于创建新的主机密钥。这将为不存在主机密钥的每种密钥类型创建新密钥,这些密钥使用默认密钥文件路径,附带空通行口令,为密钥类型使用默认位大小,并附带空注释。以下示例首先删除现有密钥,然后创建一个新集,以此创建一组全新的主机密钥:
>
sudo
rm /etc/ssh/ssh_host*
>
sudo
ssh-keygen -A
您可以通过首先仅删除要替换的密钥来替换选定的密钥对,因为 ssh-keygen -A
不会替换现有密钥。
ssh-keygen -A
创建 DSA 密钥,不过,因为不安全,这种密钥在多年前已弃用。在 OpenSSH 7.0 中仍会创建这种密钥,但由于未在 sshd_config
中列出,这些密钥会被禁用。可以放心删除 DSA 密钥。
当您想要轮换主机密钥(请参见第 22.5 节 “轮换主机密钥”)时,必须单独创建新密钥,因为它们必须与旧主机密钥同时存在。您的用户将使用旧密钥进行身份验证,然后接收新密钥列表。新密钥的名称需是唯一的,以免与旧密钥冲突。以下示例会创建新的 RSA 和 Ed25519 主机密钥,这些密钥标有创建年份和月份。请记住,新的主机密钥不能有通行口令:
>
cd /etc/ssh
>
sudo
ssh-keygen -b 4096 -f "SSH_HOST_RSA_2022_02"
>
sudo
ssh-keygen -t ed25519 -f "SSH_HOST_ED25519_2022_02"
您可以随意命名新密钥。
22.5 轮换主机密钥 #
从版本 6.8 开始,OpenSSH 包含一个支持主机密钥轮换的协议扩展。SSH 服务器管理员必须定期停用旧主机密钥并创建新密钥,例如,在密钥已被泄露,或者有必要升级到安全系数更高的密钥的情况下。在 OpenSSH 6.8 之前,如果在用户计算机上的 ssh_config
中将 StrictHostKeyChecking
设置为 yes
,则用户会看到警告,告知主机密钥已更改,因此不允许连接。然后,用户必须从其 known_hosts
文件中手动删除服务器的公共密钥,重新连接,并手动接受新密钥。任何自动 SSH 连接(例如安排的备份)都会失败。
新的主机密钥轮换方案提供了一种在不造成服务中断的情况下分发新密钥的方法。当客户端进行连接时,服务器会向其发送新密钥的列表。下次当用户登录时,系统会询问他们是否愿意接受更改。给用户几天时间进行连接并接收新密钥,之后您可以去除旧密钥。系统会自动更新用户的 known_hosts
文件,在其中添加新密钥并去除旧密钥。
设置主机密钥轮换需要在服务器上创建新密钥,并对服务器上的 /etc/ssh/sshd_config
以及客户端上的 /etc/ssh/ssh_config
进行某些更改。
首先,创建一个或多个新密钥。以下示例会创建一个新的 RSA 密钥和一个新的 Ed25519 密钥,这两个密钥都具有唯一名称和注释。一种有效的惯常做法是用创建日期命名密钥。请记住,主机密钥不能有通行口令:
#
ssh-keygen -t rsa -f ssh_host_rsa_2022-01 -C "main server"
Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ssh_host_rsa_2022-01 Your public key has been saved in ssh_host_rsa_2022-01.pub The key fingerprint is: SHA256:F1FIF2aqOz7D3mGdsjzHpH/kjUWZehBN3uG7FM4taAQ main server The key's randomart image is: +---[RSA 3072]----+ | .Eo*.oo | | .B .o.o| | o . .++| | . o ooo=| | S . o +*.| | o o.oooo| | .o ++oo.= | | .+=o+o + .| | .oo++.. | +----[SHA256]-----+#
ssh-keygen -t ed25519 -f ssh_host_ed25519_2022-01 -C "main server"
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ssh_host_ed25519_2022-01 Your public key has been saved in ssh_host_ed25519_2022-01.pub The key fingerprint is: SHA256:2p9K0giXv7WsRnLjwjs4hJ8EFcoX1FWR4nQz6fxnjxg main server The key's randomart image is: +--[ED25519 256]--+ | .+o ...o+ | | . .... o * | | o.. o = o | | .. .. o | | o. o S . | | . oo.*+ E o | | + ++==.. = o | | = +oo= o. . .| | ..=+o= | +----[SHA256]-----+
请记录指纹,供用户校验新密钥。
将新密钥名称添加到 /etc/ssh/sshd_config
,并取消注释任何使用中的现有密钥:
## Old keys HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_ecdsa_key ## New replacement keys HostKey /etc/ssh/ssh_host_rsa_2022-01 HostKey /etc/ssh/ssh_host_ed25519_2022-01
保存更改,然后重启动 sshd
:
#
systemctl restart sshd.service
用户计算机上的 /etc/ssh/ssh_config
文件必须包含以下设置:
UpdateHostKeys ask StrictHostKeyChecking yes
在客户端中通过打开 SSH 会话来测试连接到服务器,以接收新密钥列表。注销,然后重新登录。当您重新登录时,应会看到类似于以下消息的内容:
The server has updated its host keys. These changes were verified by the server's existing trusted key. Deprecating obsolete hostkey: ED25519 SHA256:V28d3VpHgjsCoV04RBCZpLo5c0kEslCZDVdIUnCvqPI Deprecating obsolete hostkey: RSA SHA256:+NR4DVdbsUNsqJPIhISzx+eqD4x/awCCwijZ4a9eP8I Accept updated hostkeys? (yes/no):yes
可以将 UpdateHostKeys ask
设置为 UpdateHostKeys yes
以自动应用更改,并避免提示用户批准更改。
更多信息:
http://blog.djm.net.au/2015/02/key-rotation-in-openssh-68.html
man 5 ssh_config、man 5 sshd_config
22.6 公共密钥身份验证 #
公共密钥身份验证使用您自己的个人身份密钥而不是用户帐户口令进行身份验证。
以下示例演示如何创建新的个人 RSA 密钥对,该密钥对带有注释,使您知道其用途。首先切换到您的 ~/.ssh
目录(如果该目录不存在,请创建),然后创建新的密钥对。为该密钥对创建一个安全系数高的通行口令,并将该通行口令写入到安全位置:
>
cd ~/.ssh
>
ssh-keygen -C "web server1" -f id-web1 -t rsa -b 4096
接下来,将新的公共密钥复制到您要访问的计算机。您在此计算机上必须已有一个用户帐户并且可以进行 SSH 访问,这样才能通过网络复制该密钥:
>
ssh-copy-id -i id-web1 user@web1
然后尝试使用新密钥登录:
>
ssh -i id-web1 user@web1
Enter passphrase for key 'id-web1': Last login: Sat Jul 11 11:09:53 2022 from 192.168.10.122 Have a lot of fun...
系统应该会要求您提供私用密钥通行口令,而不是您的用户帐户的口令。
要使公共密钥身份验证起作用,应在远程计算机上强制实施这种身份验证方法,并且不要允许口令身份验证(请参见例 22.1 “示例 sshd_config”)。如果您在远程计算机上尚未获得公共密钥身份验证访问权限,则无法使用 ssh-copy-id
复制新的公共密钥,而必须使用其他方式,例如手动将其从 USB 记忆棒复制到远程用户帐户的 ~/.ssh/authorized_keys
文件。
22.7 无通行口令公共密钥身份验证 #
这是不使用通行口令的公共密钥身份验证。新建不带通行口令的私用身份密钥,然后像使用受通行口令保护的密钥一样使用新密钥。这对于脚本和 cron 作业等自动化服务很有用。但是,成功窃取私用密钥的任何人都可以轻松伪装为您的身份,因此您需要保护好无通行口令的私用密钥。
如果不使用无通行口令的密钥,您可以改用 gnome-keyring
,它能够记住并为您应用私用密钥和通行口令。gnome-keyring
适用于 GNOME 桌面会话(第 22.9 节 “使用 gnome-keyring 自动进行公共密钥登录”)。
对于控制台会话,请使用 ssh-agent
(第 22.10 节 “使用 ssh-agent 自动进行公共密钥登录”)。
22.8 OpenSSH 证书身份验证 #
OpenSSH 在 OpenSSH 5.4 中引入了证书身份验证。证书身份验证与公共密钥身份验证类似,不同之处在于,对于前者,主机和用户使用数字签名的加密证书而不是加密密钥向彼此进行身份验证。证书身份验证提供服务器和用户证书的集中管理,无需手动将用户公共密钥复制到多个主机。它通过为管理员提供更多控制权、为用户提供更少控制权来提高安全性。
证书由公共加密密钥、用户定义的身份字符串、零个或多个用户名或主机名以及其他选项组成。用户和主机公共密钥由证书颁发机构 (CA) 私用签名密钥签名,以创建加密证书。用户和主机信任公共 CA 密钥,而不是信任单个用户和主机公共加密密钥。
传统的 OpenSSH 公共密钥身份验证需要将用户公共密钥复制到他们需要访问的每个 SSH 服务器(复制到相应的 ~/.ssh/authorized_keys
文件),并依赖用户在接受新的 SSH 服务器主机密钥之前校验这些密钥(存储在 ~/.ssh/known_hosts
中)。这很容易出现错误,并且难以管理。另一个缺点是 OpenSSH 密钥永不失效。当您需要撤消特定的公共密钥时,必须在网络上找到并去除该密钥的所有副本。
将整个过程自动化(例如使用 Ansible)确实很有必要。像 Meta 这样的大型组织(请参见 https://engineering.fb.com/2016/09/12/security/scalable-and-secure-access-with-ssh/)已完全将此过程自动化,因此他们可以根据需要随时撤消和替换证书(甚至包括证书颁发机构),而不会中断运营。
要做到这一点,前提是能够与网络上的所有主机建立 SSH 会话,并可执行编辑配置文件和重启动 sshd
等任务。
设置 OpenSSH 证书颁发机构涉及以下步骤:
设置一个安全的可信服务器,以托管用来为主机和用户密钥签名的证书颁发机构。创建一个新密钥对用来为密钥签名。私用密钥为用户和主机密钥签名,而公共密钥将复制给有权访问服务器的所有用户。
接收主机公共密钥并为其签名,然后将新的主机证书分发给相应的主机。与主机密钥一样,主机证书存储在
/etc/ssh
中。接收用户公共密钥并为其签名,然后将新的用户证书分发给其拥有者。与用户密钥一样,用户证书存储在
~/.ssh
中。编辑服务器和用户计算机上的配置文件,并根据需要在主机上停止再启动
sshd
。根据需要撤消证书,例如,当您怀疑证书已遭泄露、用户离职或服务器退役时。撤消证书比查找并去除所有相关公共密钥副本要简单得多。
用户和服务器管理员需创建并保护其自己的 OpenSSH 密钥。可以安全地自由共享公共密钥。可以安全地使用不安全的方法(例如电子邮件)传输新证书,因为验证证书需要提供私用密钥。
SSH 证书遵循 OpenPGP 标准而不是 SSL/TLS,证书格式是 OpenPGP 而不是 X.509。
22.8.1 设置新的证书颁发机构 #
本节介绍如何设置新的证书颁发机构 (CA)。请仔细考虑如何组织您的 CA,使其易于管理并保持高效。
请务必保护托管证书颁发机构的计算机。CA 确实是整个网络的关键所在。有权访问您的 CA 的任何人都可以创建自己的证书并不受限制地访问您的网络资源,甚至可以入侵您的服务器和 CA 本身。常见做法是使用一台仅在您需要为密钥签名时才启动的专用计算机。
最佳做法是为服务器创建一个签名密钥,并为客户端创建另一个签名密钥。如果您有大量的证书需要管理,为不同计算机上的主机和客户端创建 CA 会有帮助。如果您偏好使用一台计算机,请为每个 CA 创建其自身的目录。本节中的示例使用 /ca-ssh-hosts
和 /ca-ssh-users
。示例计算机为 ca.example.com。
如果您的安全策略要求保留用户和主机公共密钥的副本,请将它们存储在各自的子目录中,以方便跟踪并避免发生密钥名称冲突。
2020 年 2 月发布的 OpenSSH 8.2 弃用了 RSA 签名密钥。请使用 Ed25519 或 ECDSA。
以下示例会创建两个签名密钥,分别用于为主机密钥和用户密钥签名。为这两个密钥提供强通行口令:
>
sudo
ssh-keygen -t ed25519 -f /ca-ssh-hosts/ca-host-sign-key -C "signing key for host certificates"
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ca-host-sign-key Your public key has been saved in ca-host-sign-key.pub The key fingerprint is: SHA256:STuQ7HgDrPcEa7ybNIW0n6kPbj28X5HN8GgwllBbAt0 signing key for host certificates The key's randomart image is: +--[ED25519 256]--+ | o+o.. | | . . o.=E | | = + B . | | + O + = B | | . O * S = + | | o B + o . | | =o= . | | o.*+ . | | .=.o+. | +----[SHA256]-----+
>
sudo
ssh-keygen -t ed25519 -f /ca-ssh-users/ca-user-sign-key -C "signing key for user certificates"
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ca-user-sign-key Your public key has been saved in ca-user-sign-key.pub The key fingerprint is: SHA256:taYj8tTnjkzgfHRvQ6HTj8a37PY6rwv96V1x+GHRjIk signing key for user certificates The key's randomart image is: +--[ED25519 256]--+ | | | . +.| | . E o.o| | . + . ..| | . S * o .+.| | o + + = +..+| | . = * . O + o| | + = = o =oo+| | . o.o oOX=| +----[SHA256]-----+
将公共用户签名密钥(确保复制的是公共密钥)复制到运行 SSH 服务器的所有主机上的 /etc/ssh
中。然后将公共用户签名密钥的完整路径输入到主机上的 /etc/ssh/sshd_config
中:
TrustedUserCAKeys /etc/ssh/ca-user-sign-key.pub
然后重启动 sshd
。
22.8.2 创建主机证书 #
以下示例为主机公共密钥签名,以便为数据库服务器创建主机证书:
>
sudo
ssh-keygen -s /ca-ssh-hosts/ca-host-sign-key
\-n venus,venus.example.com -I "db-server host cert"
\-h -V +4w /etc/ssh/ssh_host_ed25519_key.pub
Enter passphrase: Signed host key /etc/ssh/ssh_host_ed25519_key-cert.pub: id "db-server host cert" serial 0 for venus,venus.example.com valid from 2022-08-08T14:20:00 to 2022-09-05T15:21:19
如果服务器上有多个主机密钥,请为所有这些密钥签名。
-s
是您的私用签名密钥。-n
是您的主体列表。对于主机证书,主体是计算机的主机名和完全限定的域名。-I
是身份字符串。这是您想要提供的任何注释或说明。系统会记录该字符串,以帮助您快速找到相关的日志项。-h
创建主机证书。-V
设置证书的失效日期。在该示例中,证书将在四个星期后失效。(有关允许的时间格式,请参见man 1 ssh-keygen
的“-Vvalidation_interval”部分。)
校验新证书是否按照您所需的方式构建:
>
ssh-keygen -Lf /etc/ssh/ssh_host_ed25519_key-cert.pub
/etc/ssh/ssh_host_ed25519_key-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com host certificate Public key: ED25519-CERT SHA256:/ U7C+qABXYyuvueUuhFKzzVINq3d7IULRLwBstvVC+Q Signing CA: ED25519 SHA256: STuQ7HgDrPcEa7ybNIW0n6kPbj28X5HN8GgwllBbAt0 (using ssh-ed25519) Key ID: "db-server host cert" Serial: 0 Valid: from 2022-08-08T14:20:00 to 2022-09-05T15:21:19 Principals: venus venus.example.com Critical Options: (none) Extensions: (none)
将新主机证书的完整路径添加到 /etc/ssh/sshd_config
,使其可供客户端使用:
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
重启动 sshd
以加载您的更改:
>
sudo
systemctl restart sshd.service
请参见第 22.8.3 节 “用户的 CA 配置”了解如何配置客户端以接受主机证书。
22.8.3 用户的 CA 配置 #
以下示例说明如何将客户端配置为信任您的 CA 而不是单个密钥。该示例授予对单个服务器的访问权限。此项必须在用户的 ~/.ssh/known_hosts
文件中独行提供,且不能换行。移动原始 ~/.ssh/known_hosts
文件,并创建一个仅包含 CA 配置的新文件。或者,在 /etc/ssh/ssh_known_hosts
中创建全局配置,这样做的好处是可以防止非特权用户编辑该文件:
@cert-authority db,db.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH1pF6DN4BdsfUKWuyiGt/leCvuZ/fPu YxY7+4V68Fz0 signing key for user certificates
在逗号分隔列表中列出允许用户访问的每个服务器,例如 venus,venus.example.com,saturn,saturn.example.com
。您还可以使用通配符授予对域中所有服务器的访问权限,例如 *.example.com,*.example2.com
。
尝试连接到服务器。系统应会提示您输入远程帐户的口令,而不会提示您校验主机证书。
22.8.4 创建用户证书 #
为用户的公共密钥签名:
>
sudo
ssh-keygen /ca-ssh-hosts/ca-user-sign-key -I "suzanne's cert" -n suzanne -V +52w user-key.pub
Signed user key .ssh/ed25519key-cert.pub: id "suzanne's cert" serial 0 for suzanne valid from 2022-09-14T12:57:00 to 2023-09-13T12:58:21
用户证书中的主体始终是用户名。将用户的证书存储在用户计算机上的 ~/.ssh
中。
用户证书将替换 ~/.ssh/authorized_keys
文件。从远程计算机上的用户帐户中去除此文件,然后尝试与该帐户建立 SSH 会话。您应该可以直接登录,而不会看到口令提示。(请记住,服务器应在其 /etc/ssh/sshd_config
文件中包含 TrustedUserCAKeys /etc/ssh/ca-user-sign-key.pub
行,以便知道需要信任您的证书颁发机构。)
此外,请查看日志文件中的 Accepted publickey for
suzanne
消息。
22.8.5 撤消主机密钥 #
如果您由于服务器遭到入侵或退役而需要撤消某个证书,请将该证书的相应公共密钥添加到每个客户端上的文件(例如 /etc/ssh/revoked_keys
)中:
ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIK6hyvFAhFI+0hkKehF/ 506fD1VdcW29ykfFJn1CPK9lAAAAIAawaXbbEFiQOAe5LGclrCHSLWbEeUauK5+CAuhTJyz0 AAAAAAAAAAAAAAACAAAAE2RiLXNlcnZlciBob3N0IGNlcnQAAAAeAAAABXZlbnVzAAAAEXZl bnVzLmV4YW1wbGUuY29tAAAAAGMabhQAAAAAYz9YgQAAAAAAAAAAAAAAAAAAADMAAAALc3No LWVkMjU1MTkAAAAgfWkXoM3gF2x9Qpa7KIa3+V4K+5n98+5jFjv7hXrwXPQAAABTAAAAC3Nz aC1lZDI1NTE5AAAAQI+mbJsQjt/9bLiURse8DF3yTa6Yk3HpoE2uf9FW/ KeLsw2wPeDv0d6jv49Wgr5T3xHYPf+VPJQW35ntFiHTlQg= root@db
必须在 /etc/ssh/sshd_config
中为此文件命名:
RevokedKeys /etc/ssh/revoked_keys
22.9 使用 gnome-keyring 自动进行公共密钥登录 #
安装 GNOME 桌面环境时,默认会安装并启用 gnome-keyring 软件包。gnome-keyring
与您的系统登录名集成,在登录时会自动解锁您的机密存储。当您更改登录口令时,gnome-keyring
会自动使用新口令自我更新。
对于具有 *.pub
文件的每个密钥对,gnome-keyring
会自动加载 ~/.ssh
中的所有密钥对。您可以使用 ssh-add
命令手动加载其他密钥,例如:
>
ssh-add ~/.otherkeys/my_key
列出所有已加载的密钥:
>
ssh-add -L
当您启动系统,然后打开 SSH 会话时,系统会提示您输入私用密钥通行口令。
在剩余的会话期间,gnome-keyring
会记住该通行口令。在系统重启动之前,您都不需要重新输入通行口令。
22.10 使用 ssh-agent 自动进行公共密钥登录 #
openssh 软件包提供了 ssh-agent
实用程序,该实用程序可以保留您的私用密钥和通行口令,在当前会话期间,它会自动为您应用通行口令。
可以通过在 ~/.profile
文件中输入以下几行,将 ssh-agent
配置为自动启动并加载您的密钥:
eval "$(ssh-agent)" ssh-add
第一行会启动 ssh-agent
,第二行会加载 ~/.ssh
文件夹中的所有密钥。当您打开需要公共密钥身份验证的 SSH 会话时,系统会提示您输入通行口令。提供一次通行口令后,在重启动系统之前您不需要再次输入通行口令。
可以将 ~/.profile
配置为仅加载特定的密钥,例如,以下示例仅加载 id_rsa
和 id_ed25519
:
>
ssh-add id_rsa id_ed25519
22.10.1 在 X 会话中使用 ssh-agent
#
在 SUSE Linux Enterprise Desktop 上,ssh-agent
会由 GNOME 显示管理器自动启动。要在 X 会话开始时同时调用 ssh-add
向代理添加您的密钥,请执行以下操作:
以所需用户的身份登录,并检查文件
~/.xinitrc
是否存在。如果不存在,请使用现有模板,或从
/etc/skel
复制该文件:if [ -f ~/.xinitrc.template ]; then mv ~/.xinitrc.template ~/.xinitrc; \ else cp /etc/skel/.xinitrc.template ~/.xinitrc; fi
如果您复制了该模板,请搜索以下几行并将其取消注释。如果
~/.xinitrc
已存在,请添加以下几行(不带注释符号)。# if test -S "$SSH_AUTH_SOCK" -a -x "$SSH_ASKPASS"; then # ssh-add < /dev/null # fi
启动新的 X 会话时,系统会提示您输入 SSH 通行口令。
22.11 更改 SSH 私用密钥通行口令 #
可以使用 ssh-keygen
更改或去除私用密钥的通行口令:
>
ssh-keygen -pf ~/.ssh/server1
Enter old passphrase: Key has comment 'shared videos server1' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase.
22.12 检索密钥指纹 #
使用 ssh-keygen
显示公共密钥指纹。以下示例列显 ED25519 密钥的 SHA256 哈希:
>
ssh-keygen -lf ldap-server
256 SHA256:W45lbmj24ZoASbrqW0q9+NhF04muvfKZ+FkRa2cCiqo comment (ED25519)
添加 -v
标志以显示该密钥的 ASCII 图文表示形式:
>
ssh-keygen -lvf ldap-server
256 SHA256:W45lbmj24ZoASbrqW0q9+NhF04muvfKZ+FkRa2cCiqo comment (ED25519) +--[ED25519 256]--+ | | | | | .. . | | .o..+ + | | ...o+ BSo+ | |. ..o.o =X | |...o o..* = | |o.*.* =+ = . | |E*o*+O. o.o | +----[SHA256]-----+
22.13 在远程主机上启动 X11 应用程序 #
您可以在本地计算机上运行安装在远程计算机上的图形应用程序。必须在远程计算机上的 /etc/ssh/sshd_config
文件中设置 X11Forwarding Yes
。然后,当您结合 -X
选项运行 ssh
时,远程计算机上会自动设置 DISPLAY
变量,而且所有 X 输出都将通过 SSH 连接导出到本地计算机。此外,未获授权的用户无法拦截远程启动的 X 应用程序。
从远程计算机运行一个简单游戏(例如 GNOME Mines)以进行快速测试:
>
ssh wilber@sun
Password: Last login: Tue May 10 11:29:06 2022 from 192.168.163.13 Have a lot of fun... wilber@sun>
gnome-mines
远程应用程序应显示在您的本地计算机上,就如同它安装在本地一样。(网络延迟会影响性能。)像平时一样关闭远程应用程序,例如单击“关闭”按钮。这只会关闭该应用程序,而您的 SSH 会话仍保持打开状态。
X11 转发要求远程主机上运行 X Window 系统。X Window 系统提供了内置网络功能,而 Wayland 则不提供。因此,Wayland 不支持 X11 转发。
使用以下命令来了解您的系统运行的是 X 还是 Wayland:
>
echo $XDG_SESSION_TYPE
x11
如果使用的是 Wayland,则该命令的输出如以下示例所示:
>
echo $XDG_SESSION_TYPE
wayland
systemd 检查方式是使用 loginctl
进行查询:
>
loginctl show-session "$XDG_SESSION_ID" -p Type
Type=x11>
loginctl show-session "$XDG_SESSION_ID" -p Type
Type=wayland
22.14 代理转发 #
添加 -A
选项可将 ssh-agent 身份验证机制转移到下一台计算机。这样,您就可以在不同计算机上工作而无需输入口令,但前提是:已将公钥分发给目标主机并在其上正确保存。(请参见第 22.6 节 “公共密钥身份验证”了解如何将公共密钥复制到其他主机。)
/etc/ssh/sshd_config
中的默认值为 AllowAgentForwarding yes
。将它更改为 No
可禁用此设置。
22.15 scp
— 安全复制 #
scp
将文件复制到远程计算机或从中复制文件。如果 jupiter 上的用户名不同于 sun 上的用户名,请使用 USER_NAME&host
格式指定后者的用户名。如果应将文件复制到其他目录而不是远程用户的主目录,请以 sun:DIRECTORY 形式指定该目录。下列示例显示了如何将文件从本地计算机复制到远程计算机,以及反向复制。
>
scp ~/MyLetter.tex tux@sun:/tmp 1>
scp tux@sun:/tmp/MyLetter.tex ~ 2
-l
选项
在 ssh
命令中,可以使用 -l
选项指定远程用户(替代 USER_NAME&host
格式)。在 scp
中,-l
选项用于限制 scp
所使用的带宽。
输入正确的口令后,scp
将启动数据传输。它会显示复制的每个文件的进度条和剩余时间。使用 -q
选项可以隐藏所有输出。
scp
还提供了对整个目录的递归复制功能。命令
>
scp -r src/ sun:backup/
会将目录 src
的全部内容(包括所有子目录)复制到主机 sun 上的 ~/backup
目录中。如果此子目录不存在,系统会自动创建该子目录。
-p
选项告知 scp
不要更改文件的时戳。-C
对传输数据进行压缩。这可以最大限度地减少要传输的数据量,但同时会增加两台计算机的处理器的负担。
22.16 sftp
— 安全文件传输 #
22.16.1 使用 sftp
#
与 scp
相比,使用 sftp
可以更方便地在不同位置之间复制多个文件。它会打开一个外壳,其中包含一组与普通 FTP 外壳类似的命令。在 sftp 提示符处键入 help
可获取可用命令的列表。sftp
手册页中提供了更多细节。
>
sftp sun
Enter passphrase for key '/home/tux/.ssh/id_rsa':
Connected to sun.
sftp> help
Available commands:
bye Quit sftp
cd path Change remote directory to 'path'
[...]
22.16.2 设置文件上载权限 #
与使用普通的 FTP 服务器一样,用户可以下载文件,并可以使用 put
命令将文件上载到运行 SFTP 服务器的远程计算机。默认情况下,向远程主机上载文件时将使用与本地计算机上相同的权限。有两个选项可以自动更改这些权限:
- 设置 umask
umask 充当本地主机上原始文件的权限的过滤器。它还可以撤回权限:
原始权限
umask
上载的权限
0666
0002
0664
0600
0002
0600
0775
0025
0750
要在 SFTP 服务器上应用 umask,请编辑文件
/etc/ssh/sshd_configuration
。搜索以Subsystem sftp
开头的行,并添加包含所需设置的-u
参数,例如:Subsystem sftp /usr/lib/ssh/sftp-server -u 0002
- 明确设置权限
明确设置权限会为通过 SFTP 上载的所有文件设置相同的权限。使用
-u
指定三位数模式,例如600
、644
或755
。如果同时指定-m
和-u
,将忽略-u
。要在 SFTP 服务器上为上载的文件应用明确权限,请编辑文件
/etc/ssh/sshd_config
。搜索以Subsystem sftp
开头的行,并添加包含所需设置的-m
参数,例如:Subsystem sftp /usr/lib/ssh/sftp-server -m 600
要监测 sshd
中的日志项,请使用以下命令:
>
sudo
journalctl -u sshd
22.17 端口转发(SSH 隧道) #
ssh
还可用于重定向 TCP/IP 连接。此功能也称为 SSH tunneling
,它通过加密的通道将定向到特定端口的 TCP 连接重定向到另一台计算机。
使用以下命令可将定向到 jupiter 端口 25 (SMTP) 的所有连接重定向到 sun 上的 SMTP 端口。如果用户所用的 SMTP 服务器不具备 SMTP-AUTH 或 POP-before-SMTP 功能,此命令特别有用。从与网络相连的任意位置都可以将电子邮件传送到“家庭”邮件服务器进行递送。
#
ssh -L 25:sun:25 jupiter
同样,使用以下命令可将 jupiter 上的所有 POP3 请求(端口 110)转发到 sun 的 POP3 端口:
#
ssh -L 110:sun:110 jupiter
必须以 root
身份执行这两个命令,因为连接指向有特权的本地端口。普通用户通过现有 SSH 连接发送和检索电子邮件。为此,必须将 SMTP 和 POP3 主机设置为 localhost
。上述每个程序的手册页以及 /usr/share/doc/packages/openssh
下的 OpenSSH 软件包文档中提供了更多信息。
22.18 更多信息 #
- https://www.openssh.com
OpenSSH 主页
- https://en.wikibooks.org/wiki/OpenSSH
OpenSSH Wikibook
man sshd
OpenSSH 守护程序的手册页
man ssh_config
OpenSSH SSH 客户端配置文件的手册页
man scp
,man sftp
,man ssh
,man ssh-add
,man ssh-copy-id
,man ssh-keygen
用于安全复制文件(
scp
、sftp
)、用于登录(slogin
、ssh
)和用于管理密钥的多个二进制文件的手册页。-
/usr/share/doc/packages/openssh-common/README.SUSE
,/usr/share/doc/packages/openssh-common/README.FIPS
SUSE 软件包的相关文档;上游相关默认设置的更改、有关 FIPS 模式的说明等。
22.19 使用 Fail2Ban 阻止 SSH 暴力破解 #
SSH 暴力破解是指反复尝试用户名和口令组合,直到攻击者获得对远程服务器的访问权限。攻击者会使用自动化工具来测试各种用户名和口令组合,以图入侵服务器。
您可以使用 Fail2Ban 软件来限制入侵尝试。Fail2Ban 会扫描系统日志以检测攻击并触发相应操作,例如通过防火墙阻止 IP。Fail2Ban 仅用于保护要求进行用户名和口令身份验证的服务。
22.19.1 什么是 Fail2Ban? #
Fail2Ban 会扫描 /var/log/apache/error_log
中的日志文件,并会禁止表现出恶意迹象的 IP(例如口令尝试次数过多)等。然后,您便可以使用 Fail2Ban 更新防火墙规则,将相应 IP 地址拒绝一段指定的时间。
Fail2Ban 随附了各种服务(例如 Apache、SSH、Courier 等)的过滤器。借助 Fail2Ban,您可以最大限度地降低错误身份验证尝试的比率。
22.19.2 使用 Fail2Ban 阻止 SSH 暴力破解 #
您可以安装并配置 Fail2Ban 来帮助服务器抵御 SSH 暴力破解。
要安装 Fail2Ban,请执行以下命令:
#
sudo zypper -n in fail2ban firewalld安装 Fail2Ban 时,还会安装默认配置文件
jail.conf
。升级 Fail2Ban 时,此文件会被覆盖。要保留您对该文件进行的任何自定义设置,可以将修改添加到名为 jail.local 的文件中。Fail2Ban 会自动读取这两个文件。#
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local在编辑器中打开该文件。
vi /etc/fail2ban/jail.local
查看您需要了解的四个设置。
图 22.1︰ jail.local 文件设置 #- ignoreip
加入白名单的 IP 的列表,这些 IP 永远不会被禁止。默认情况下,本地主机 IP 地址 127.0.0.1 以及等效的 IPv6 IP ::1 都包含在列表中。您可以使用此设置来添加您确定不应被禁止的 IP 地址列表。
- bantime
禁止 IP 地址的时长(以分钟为单位)。如果输入的值不是以 m 或 h 结尾,则将时长视为以秒为单位。如果输入值 -1,则 IP 地址将被永久禁止。
- findtime
因连接尝试失败次数过多而导致 IP 被禁止的时间段。
- maxretry
失败的尝试次数上限。
注意如果来自同一 IP 地址的连接在 findtime 期间进行了 maxretry 次失败的连接尝试,则在 bantime 内将禁止这些连接。唯一的例外是 ignoreip 列表中的 IP 地址。
Fail2Ban 支持不同类型的 jail,每个 jail 针对各连接类型都会使用不同的设置。
您可以运行以下命令来使用 Fail2Ban 服务:
启用该服务:
#
systemctl enable fail2ban启动该服务:
#
systemctl start fail2ban检查服务状态:
#
systemctl status fail2ban.service重要每次更改配置时,都必须重启动 Fail2Ban。