跳转到内容

OpenSSH/Cookbook/负载均衡

100% developed
来自 Wikibooks,开放的书籍,为开放的世界

 

MaxStartups

[编辑 | 编辑源代码]

可以通过指定三个冒号分隔的值 start:rate:full 来启用随机早期丢弃。当未经身份验证的连接数量达到 start 指定的值后,sshd(8) 将以 rate 指定的百分比开始拒绝新连接。随着 full 指定的限制被接近,拒绝连接的比例会线性增加,直到达到 100%。在这一点上,所有新的连接尝试都会被拒绝,直到积压量下降。

MaxStartups   10:30:100

例如,如果在 sshd_config(5) 中给出 MaxStartups 5:30:90,那么从 5 个新的连接等待身份验证开始,服务器将开始丢弃 30% 的新连接。当积压量增加到 90 个待处理的未经身份验证的连接时,将丢弃 100%。

在默认设置中,full 的值已增加到 100 个待处理的连接,以使其更难受到攻击或高负载导致的拒绝服务攻击的影响。因此,新的默认值为 10:30:100。

或者,如果传入连接的数量没有通过数据包过滤器或其他技巧(如轮询 DNS)在网络级别进行管理,则可以在 SSH 服务器本身限制它。将 MaxStartups 设置为整数将对 SSH 守护程序的最大并发未经身份验证的连接数设置一个硬限制。

MaxStartups   10

其他连接将被丢弃,直到身份验证成功或另一个连接的 LoginGraceTime 到期。旧的默认值为 10。

防止非活动会话超时

[编辑 | 编辑源代码]

在 SSH 会话期间可以跟踪两种连接,即网络的 TCP 连接和在其上运行的加密 SSH 会话。一些隧道和 VPN 可能并不总是处于活动状态,因此存在会话超时甚至路由器或防火墙上的 TCP 会话超时的风险。网络连接可以使用 TCPKeepAlive 进行跟踪,但这并不是实际 SSH 连接状态的准确指标。但是,它是实际网络状态的一个有用指标。客户端或服务器都可以通过使用心跳来保持加密连接处于活动状态来解决这个问题。

在客户端,如果全局客户端配置尚未设置,个人可以使用 ServerAliveInterval 选择服务器活动心跳的间隔(以秒为单位),并使用 ServerAliveCountMax 设置相应的允许的最大错过客户端消息数,在超过这个限制后,加密的 SSH 会话将被视为已关闭。

ServerAliveInterval  15
ServerAliveCountMax  4

在服务器端,ClientAliveInterval 设置客户端活动心跳之间的间隔(以秒为单位)。ClientAliveCountMax 设置允许的最大错过客户端消息数,在超过这个限制后,加密的 SSH 会话将被视为已关闭。如果在该时间段内没有发送或接收其他数据,sshd(8) 将通过加密通道发送一条消息,以请求客户端响应。如果 sshd_config(5)ClientAliveInterval 设置为 15,并将 ClientAliveCountMax 设置为 4,则无响应的 SSH 客户端将在大约 60 (= 15 x 4) 秒后断开连接。

ClientAliveInterval  15
ClientAliveCountMax  4

如果还使用了基于时间的 RekeyLimit,但时间限制短于 ClientAliveInterval 心跳,那么较短的重新密钥限制将用于心跳间隔。

这与服务器的原理大致相同。同样,它是在 ~/.ssh/config 中设置的,可以全局应用于来自该帐户的所有连接,也可以使用 HostMatch 块选择性地应用于特定连接。

确保非活动交互式会话超时

[编辑 | 编辑源代码]

如果服务器在达到 ClientAliveInterval 选项配置的超时时间时不再断开空闲的 SSH 帐户,则解决方法是将 shell 的 TMOUT 变量设置为所需的超时值。当 TMOUT 设置后,它指定 shell 在关闭 shell 以及 SSH 会话之前等待输入行的秒数。请注意,这意味着按下 Enter 键,因为其他键入本身不足以防止超时,并且必须实际输入行才能重置计时器。

在服务器上,检查 SSH_CONNECTION 变量是否存在,该变量通常为空,除非当前处于 SSH 会话中,以便将 SSH 会话与本地 shell 区分开来。如果允许帐户更改超时,则以下内容可以放在帐户自己的配置文件中,例如 ~/.profile 中,

if [ "$SSH_CONNECTION" != "" ]; then
        # 10 minutes
        TMOUT=600
        export TMOUT
fi

如果帐户不能更改此设置,则它必须放在全局配置文件中并设置为只读,例如在 /etc/profile.d/ 下的某个地方,

if [ "$SSH_CONNECTION" != "" ]; then
        # 10 minutes
        TMOUT=600
        readonly TMOUT
        export TMOUT
fi

以上两个示例适用于 Bourne shell、其派生程序以及可能的一些其他 shell。一些 shell 可能提供其他选项,例如在 tcsh(1) 中找到的实际 autologout 变量。

TCP Wrappers,也称为 tcpd(8)

[编辑 | 编辑源代码]

从 6.7 版本开始,OpenSSH 的 sshd(8) 不再支持 TCP Wrappers,也称为 tcpd(8)。因此,本小节仅适用于 6.6 及更早版本。可以使用 tcpd(8) 的其他选项包括数据包过滤器,如 PF [1]、ipf、NFTables,甚至旧的 IPTables。特别是,OpenSSH 服务器的 Match 指令支持通过 CIDR 地址进行过滤。使用这些替代方案,并牢记短语“等效的安全控制”,这可以平息由安全审计人员造成的麻烦,这些审计人员可能仍在他们的工作表上保留着一个“tcpwrappers”复选框,这些工作表来自 20 世纪 90 年代。

tcpd(8) 程序是一个用于对传入的互联网服务请求进行访问控制的工具。它用于与可执行文件之间具有一对一映射的服务,例如 sshd(8),并且这些服务已编译为与之交互。它首先检查白名单(/etc/hosts.allow),然后检查黑名单(/etc/hosts.deny)以批准或拒绝访问。与任何给定连接尝试匹配的第一个模式将被使用。/etc/hosts.deny 中的默认行为是阻止访问,如果在 /etc/hosts.allow 中没有找到匹配的规则。

sshd: ALL

除了访问控制之外,还可以设置 tcpd(8) 以在触发规则时使用 twist 或 spawn 运行脚本。spawn 将另一个程序作为 tcpd(8) 的子进程启动。来自 /etc/hosts.allow

sshd: .example.org : allow
sshd: .example.com : spawn \
	/bin/date -u +"%%F %%T UTC from %h" >> /var/log/sshd.log : allow

变量 %h 展开为连接客户端的主机名或 IP 地址。hosts_access(5) 的手册页包含对可用变量的完整描述。由于示例中的程序 date 使用相同的变量符号,因此转义字符 (%) 必须转义 (%%),这样 tcpd(8) 会忽略它,并正确地传递给 date。

twist 用另一个程序替换请求的服务。它有时用于蜜罐,但实际上可以用于任何用途。来自 /etc/hosts.deny

sshd: .example.org : deny
sshd: ALL : twist /bin/echo "Sorry, fresh out." : deny

使用 TCP Wrappers,首先搜索白名单 /etc/hosts.allow,然后搜索黑名单 /etc/hosts.deny。应用第一个匹配项。如果未找到任何适用的规则,则默认情况下授予访问权限。它不应该再被使用,应该使用更好的替代方案。另请参阅 sshd_config(5) 中关于 CIDR 地址的 Match 指令,或者 AllowUsersDenyUsers 指令。

使用 TCP Wrappers 仅允许来自特定子网的连接

[编辑 | 编辑源代码]

可以使用 TCP Wrappers,只需设置 sshd(8) 仅监听本地地址,不接受任何外部连接。这是一种方法。要使用 TCP Wrappers,请在 /etc/hosts.deny 中添加一行,阻止所有内容

sshd: ALL

并在 /etc/hosts.allow 中添加一个例外,通过使用 CIDR 表示法指定 IP 范围或使用域名来指定

sshd: 192.0.32.0/20

可以使用相同的方法限制仅允许来自 localhost (127.0.0.0/8) 的访问,方法是在 /etc/hosts.allow 中添加一行

sshd: 127.0.0.0/8

同样,最佳实践是先从所有地方阻止,然后打开例外。请记住,如果使用域名而不是 IP 范围,则 DNS 条目必须按顺序排列,并且 DNS 本身必须可访问。但是,以上仅具有历史意义。使用 sshd_config(5) 进行相应设置,并使用 OpenSSH 服务器中的 Match 指令或操作系统本身的包过滤器来代替使用 TCP Wrappers,可以更好地实现这种限制。

扩展互联网服务守护程序 (xinetd)

[编辑 | 编辑源代码]

扩展互联网服务守护程序 xinetd(8) 可以提供多种类型的访问控制。其中包括但不限于远程主机的名称、地址或网络以及时间。它可以限制每个服务的服务数量,并在负载超过一定限制时停止服务。

超级服务器监听传入请求,并根据需要启动 sshd(8),因此有必要先停止 sshd(8) 作为独立守护程序运行。这可能意味着修改 System V 初始化脚本或 Upstart 配置文件。然后为 SSH 服务创建一个 xinetd(8) 配置文件。它可能位于 /etc/xinetd.d/ssh 中。参数 -i 非常重要,因为它告诉 sshd(8) 它正在从 xinetd(8) 运行。

service ssh
{
	socket_type     = stream
	protocol        = tcp
	wait            = no
	user            = root
	server          = /usr/sbin/sshd
	server_args     = -i
	per_source      = UNLIMITED
	log_on_failure  = USERID HOST
	access_times    = 08:00-15:25
	banner          = /etc/banner.inetd.connection.txt
	banner_success  = /etc/banner.inetd.welcome.txt	
	banner_fail     = /etc/banner.inetd.takeahike.txt

	# log_on_success  = PID HOST DURATION TRAFFIC EXIT
	# instances       = 10
	# nice            = 10
	# bind            = 192.168.0.100
	# only_from       = 192.168.0.0
	# no_access       = 192.168.54.0
	# no_access       += 192.168.33.0
}

最后,通过向 xinetd(8) 发送 SIGHUP 来重新加载配置。


参考文献

[编辑 | 编辑源代码]
  1. Peter N M Hansteen (2011). "使用 PF 防火墙".

 

华夏公益教科书