第十二章:自动化

SSH是一个非常强大的自动化工具。许多程序可以使用SSH作为传输,依靠已知的安全软件,而不是试图实现自己的网络安全。大多数网络编排工具,如Ansible和Puppet,都是用SSH;破坏SSH配置意味着你无法使用它们。

然而,这种灵活性也可能导致安全问题。自动化流程不应该访问任何东西,除了执行任务所需的最低限度。幸运的是,你可以限制特定用户可以通过SSH、authorized_keys 文件甚至 sshd 本身运行的命令。此外,你可以在用户登录时自动运行命令。我们将从该功能开始,然后继续限制用户。

第十二章:自动化登录时运行命令authorized_keys 限制Authorized_keys 格式command="command"environment="NAME=value"from="ssh-pattern"no-agent-forwardingno-x11-forwardingno-ptyno-user-rcpermitopen="host:port"tunnel="n"restict使用多个关键字密钥和自动化程序自动化身份验证密钥限制自动化密钥开发自动化脚本服务器端限制自动化和 root 登录

登录时运行命令

SSH服务器在用户启动新会话时检查要运行的命令。这主要是为了配置使账户在登录前可用所需的服务,例如挂载文件系统和分配X显示,但你可以根据需要使用它。

登录时,sshd 检查shell脚本 $HOME/.ssh/rc 。如果它存在,就运行它。如果不存在, sshd 会检查 /ssh/sshrc 上的脚本并运行该脚本。无论哪种方式,脚本都由登录的账户运行。如果每次用户登录时都需要执行任务,请考虑此功能。

该脚本必须是有效的shell脚本,在文件顶部带有 #!/bin/sh ,并且它必须是可执行的(一些Linux发行版即使不符合这些要求也会执行此命令)。SSH守护进程向脚本传递一个参数,即X11 cookie。使用现代X软件,你几乎可以忽略它。

sshd_config 关键字 PermitUserRC 打开和关闭脚本检查。虽然它默认为 yes ,但可以通过将其设置为 no 来禁用该脚本。

authorized_keys 限制

虽然用户的 authorized_keys 指定了可用于身份验证的密钥对,但你也可以使用它来限制使用该密钥登录的用户可能运行的命令。一个账户可能有一个用于交互式使用的密钥对,还有一个用于自动任务的密钥对。配置需要了解 authorized_keys 文件格式。

Authorized_keys 格式

最小 authorized_keys 条目有三个部分:密钥类型、表示公钥的几百个字符和注释字段。所有条目都在同一行上,无论它有多长。像以下示例:

这是一个RSA密钥,条目开头显示了ssh-rsa。公钥从AAA开始,到8Rs/Q==结束。大多数公钥条目都以 == 结尾,但也有例外。末尾的注释会向主机提供此密钥创建的日期和时间。

你可以在条目的开头添加其他关键字和如何使用此密钥的说明。服务器在用户权限范围内遵守这些指令。在 sshd(8) 手册页中有 authorized_keys 关键字的完整列表。以下是最常用的关键字:

command="command"

每当有人使用此密钥登录时,运行指定的命令。SSH忽略用户提供的任何命令,而选择 authorized_keys 指定的命令。你可以将其用于自动化过程,例如配置VPN(第13章)或运行 rsync

一个有趣的特性是,SSH保留了客户端在环境变量 $SSH_ORIGINAL_COMMAND 中请求的任何命令。你可以让 authorized_keys 运行一个脚本,检查此环境变量并采取适当的行动。(“备份帐户刚刚请求访问 /bin/bash ?你好,系统管理员,我们有问题…”)

environment="NAME=value"

当使用此密钥登录时,会设置一个环境变量。你可以使用任意数量的环境语句。

默认情况下, sshd 不允许设置环境变量。系统管理员必须在 sshd_config 中将 PermitUserEnvironment 设置为 yes ,以便用户设置环境变量。

from="ssh-pattern"

只有当客户端地址或反向DNS与给定模式匹配时,此密钥才能用于身份验证。我们在第2章讨论了模式。我经常用它来限制自动化流程。即使入侵者窃取了私人用户密钥,他也无法从我允许的主机之外的任何主机访问SSH服务器。

只有IP范围为192.51.100.0到192.51.100.7的主机才能使用此密钥登录SSH服务器。

如果UserDNS设置为 yes ,则只能在模式中使用主机名。请记住,入侵者经常可以伪造他们的反向DNS条目,因此最好在 sshd 中禁用DNS并坚持使用IP地址。

no-agent-forwarding

使用此密钥将禁用SSH代理转发(参见第7章):

no-x11-forwarding

禁用X转发(参见第8章):

no-pty

使用此密钥进行身份验证的会话将不会被授予伪终端(pseudo-terminal)。许多在自动化下运行的程序不需要终端。

no-user-rc

这将禁用 sshd 的登录脚本检查,如本章开头的“登录时运行命令”中所述:

permitopen="host:port"

permitopen 关键字限制本地端口转发,使其只能连接到本地计算机上的给定主机名或IP地址和端口。如果服务器不允许本地端口转发,则此操作无效。

此示例允许端口转发连接到127.0.0.1上的端口25,但仅此而已。

你可以将 permitopen 设置为 none 以禁止所有端口转发。

tunnel="n"

为SSH隧道使用特定的隧道设备号(见第13章)。

restict

默认情况下,任何未被拒绝的内容都是允许的。restrict 关键字反转了这一点,除非你特别允许,否则会组织所有内容。你可以使用关键字 agent-forwardingport-forwardingptyuser-rcX11-forwarding 来重新打开这些功能。

使用多个关键字

与OpenSSH中几乎所有内容一样,你可以在一个条目中使用多个关键字。用逗号分隔关键字:

密钥和自动化程序

我们很多人都想使用SSH作为其他程序的安全传输。也许你有一个自定义的监视器程序,或者一个在 rsync 上运行的备份进程。此类客户不应该拥有硬编码的用户名和密码;除了不安全之外,它既不可维护也不可扩展。一种解决方案是使用没有密码的身份验证密钥。通过严格限制该密钥的使用方式以及可以对该密钥采取的操作,可以最大限度地减少入侵者造成的伤害。

注意,潜在的损害只是被最小化,而不是被消除。在错误时间允许 rsync 备份可能会损坏现有的良好备份或使网络饱和。在错误时间启动VPN可能会造成严重破坏。然而,在大多数环境中,这些比复制或销毁你所有专有数据的人破坏性更小、更明显。

首先,你需要一个适合程序使用的用户密钥,然后,需要适当的 authorized_keys 限制。

自动化身份验证密钥

自动流程无法键入密码短语。任何需要SSH访问另一台主机的计划或其他自动化任务都需要一个没有密码短语的密钥。生成此密钥,就像生成主机密钥一样:

这将创建两个文件,一个具有你选择的文件名,另一个具有相同的名称但附加了 .pub 。这里,我创建了一个名为 task-key 的密钥:

我最终得到了文件 task-keytask-key.pub.pub 文件是公钥。

在SSH服务器上为此自动任务创建一个账户,或选择一个现有账户。主机的SSH服务器必须允许登录该账户。将 .pub 文件添加到该账户的 authorized_keys 中。

客户端机器现在应该能够使用密钥登录到SSH服务器。记得使用 ssh(1)-i 参数指定备用密钥文件。此处,我使用此密钥登录到机器 sloth

如果你成功登录到服务器,则密钥已经正确安装。现在我们把它锁起来。

限制自动化密钥

最佳实践禁止用户执行任务所需的所有访问。你的自动化流程需要端口还是X转发?关掉它们。它需要一个特殊的环境吗?可能不会,因为你可以在用户账户中更容易地建立该环境。你的自动化作业在一台机器上运行,因此你可以限制密钥,使其只能在这台机器上使用。你可能会得到这样的 authorized_keys 条目:

这样配置密钥可以减少灾难的范围。备份脚本不会意外覆盖你的根分区。入侵者只能运行你的备份脚本。这并不好,但总比入侵者窃取你的数据并删除你的日志文件好。

开发自动化脚本

限制密钥的一个挑战是了解程序实际需要什么命令,以及你认为它需要什么。sshd 的调试模式可以帮助你解决这个问题。让你的客户端在调试模式下对 sshd 运行其命令,并研究输出。你将看到客户端运行的所有命令。这也将使你能够比其他方式更进一步地锁定密钥——如果你知道 rsync 将在你的服务器上使用的确切标志,你可以将其作为限制。

有时编写的脚本似乎可以在命令行中工作,但在计划时失败了,每次我的脚本都是从我的SSH代理获取身份验证信息,而不是使用我为任务创建的密钥。IdentitiesOnly关键字告诉 ssh(1) 只使用命令行中指定的标识,而不使用代理。在脚本的SSH命令中设置 -o IdentitiesOnly=yes

自动脚本不应该提示用户输入。你不希望脚本挂起并等待密码提示。BatchMode 关键字禁用密码和密码提示。通过 BatchMode 设置为 yes ,脚本的SSH部分将立即崩溃并死亡,而不是永远无意义地徘徊。

服务器端限制

也许你不想使用 authorized_keys 来限制访问,或者你可能要额外的保护。你可以使用 ForceCommand sshd_config 关键字来限制账户可以运行的内容。

ForceCommand 接受一个参数,即要运行的命令。它在用户的常规权限下运行,忽略客户端请求的任何命令。与在 authorized_keys 中定义命令非常相似,ForceCommand$SSH_ORIGINAL_COMMAND 环境变量中保留了请求的命令。

ForceCommand 最好在 Match 语句中使用。

自动化和 root 登录

"我的命令需要以root身份运行!”可以使用 PermitRootLogin 关键字以 root 身份登录。不要这样做。以 root 身份登录自动化违反了许多基本的安全原则。将您的自动化脚本与远程根权限相信任是度过一个不定期的周末从备份中恢复服务器的好方法。(您确实有 rsync 之外的备份,对吧?请记住,rsync 是一种策略,而不是战略。)

是的,一些环境可以安全地支持 root 登录。有些人以支持审计的方式使用 root 登录。然而,如果你读这本书是为了了解SSH,那么你的环境还远没有为此做好准备。

如果您的自动化流程需要特权访问,请使用 sudosudohttps://www.sudo.ws)允许无特权用户以提升的权限运行特定命令,适用于每个类Unix系统。我不打算详细介绍如何使用 sudo ;如果你需要教程,可以查看任意数量的网站或我的书《Sudo Mastery》(倾斜风车出版社,2013)。sudo 比大多数人想象的要灵活得多,也更危险。

在下一章中,我们将使用受限密钥通过SSH构建VPN。