特种用途 sshd 最佳实践

作者:Don Marti

OpenSSH 是系统管理员工具箱的标准组成部分。虽然 sshd,即 OpenSSH 守护进程,功能多样,但有时您需要多个守护进程才能满足您的安全目标。

您为什么要运行额外的 sshd 呢?

首先,是紧急情况。您搞砸了一些东西,尝试重启 sshd,但它没有恢复。这意味着要么亲自去访问系统(可能路途遥远),要么如果您运行了另一个 sshd,则可以使用它重新进入并修复常规的 sshd。

其次,存在安全策略方面的考虑。您始终可以运行一个 sshd 并使其侦听两个接口,但这对于“堡垒主机”系统可能不合适,在堡垒主机系统中,您希望面向外部的网络接口尽可能安全,并为来自面向内部的网络接口的人员提供更多功能。

例如,您可能希望每个人都能够从他们的桌面系统 ssh 连接到 shell 服务器,但只允许系统管理员和网站管理员从外部进入。不幸的是,您无法执行仅适用于一个接口的 AllowUsers。如果您想要两组 AllowUsers 用户,则需要两个 sshd。

PermitRootLogin 也是如此。

另一个简单但有用的安全措施是保护以明文形式发送敏感信息的守护进程,方法是将它们配置为仅侦听环回接口,以便只有 localhost 可以连接到它。如果您想向网络提供服务,这有什么好处呢?很简单。通过使守护进程仅绑定到环回接口(使用 Apache 的 BindAddress 或类似的配置指令),您强制远程用户必须使用 ssh 隧道。但是,与此同时,您可能希望阻止普通用户在该主机上获得 shell 访问权限。

您可以使用 sshd_config 中的 AllowTcpForwarding no 来阻止用户设置 ssh 端口转发。(正如手册页所提到的,如果用户可以在系统上安装自己的端口转发软件,则这不是万无一失的。)但是,如何使用户只能进行端口转发,而不能登录呢?

使用旧的 Un*x 技巧,将用户的 shell 设置为 /bin/false。您可以创建任意数量的仅隧道帐户。要允许用户访问其中一个帐户,只需将该用户的 ssh 公钥复制到仅隧道帐户的 .ssh/authorized_keys 中即可。

额外的 init 脚本

运行两个 sshd 副本的最简单方法是拥有两个 init 脚本和两个配置文件。幸运的是,这很简单。只需 cd 到 /etc/ssh,或您的 sshd_config 文件所在的任何位置,然后将其 cp 到 /etc/ssh/extra_sshd_config,或类似 admin_group_sshd_config 这样的描述性名称。在新文件中,更改 Port 行或 ListenAddress 行,以便您的额外 sshd 不会与您的常规 sshd 位于相同的端口/接口组合上。(在这里,我使用端口 22222,但您也可以使用希望未使用的 telnet 端口,端口 23)。如果您的系统有两个或多个网络接口,您可以拥有两个 sshd 实例,都在端口 22 上,但接口不同。您可以使用 sshd -f /etc/ssh/extra_sshd_config 测试此步骤。现在复制您的 ssh init 脚本,它可能位于 /etc/init.d/ 或 /etc/rc.d/init.d 中。将副本命名为 extra_sshd,或类似 admin_group_sshd 这样的描述性名称。在副本中,将命令行选项 -f /etc/ssh/extra_sshd_config 添加到任何提及 sshd 的地方。使用参数 "start" 运行脚本,您应该能够执行 ssh -p 22222 localhost。

您现在可以使用您的发行版的标准工具将新的 init 脚本添加到适当的运行级别,或者只需使用 ln -s 手动完成。

从 /etc/inittab 启动

Linux Gazette 的 Jim Dennis 指出,在严重混乱的系统上,“可怕的 OOM killer”(一种内核功能,用于杀死进程以尝试从内存不足的情况中恢复)可能会干掉从 /etc/init.d/ 或 /etc/init.d/rc.d 中的 init 脚本启动的 sshd。这使您无法进入最需要的混乱系统。答案是从 /etc/inittab 直接启动第二个紧急 sshd。如果从 /etc/iniittab 启动的进程死亡,init 将重新启动它。

为了直接从 inittab 运行 sshd,添加如下行:ss:12345:respawn:/usr/sbin/sshd -D -f /etc/ssh/extra_sshd_config

并执行 kill -HUP 1 以使 init 重新读取 /etc/inittab。

等一下!为什么使用 -D 表示“不要变成守护进程”?当从 init 脚本启动的进程变成守护进程时,它会经历一个小的舞蹈,其中原始的 sshd 进程退出,并且它的一个后代在后台作为 init 的子进程运行。由于我们直接从 /etc/inittab 启动 sshd,因此原始进程已经是 init 的子进程,因此我们不需要这样做。这样做会使 init 非常困惑,当它跟踪的原始进程死亡时,它会认为必须不断重启 sshd。

这种方法的优点是,如果 OOM killer 杀死额外的 sshd,或者如果由于某种偶然性导致它死亡,init 将重新启动它。后者从未发生在我身上,但您永远不会知道。要停止从 inittab 启动的 sshd,只需注释掉 /etc/inittab 行并执行 kill -HUP 1。

现在您可能对如果您在系统上运行另一个 sshd 可以做的有趣事情有一些想法。重要的是从您想要执行的安全策略开始,并将 ssh 用作帮助实现该策略的工具,而不仅仅是调整它直到它可以工作。

电子邮件: dmarti@ssc.com

加载 Disqus 评论