关于锁定 Linux 和 FreeBSD 用户帐户的警示故事

大号与其他所有独立开发人员和系统管理员一样,我使用 ssh 做事。 有些东西是使用脚本自动完成的,有些则需要 ssh 登录。 例如,我的一个脚本使用公共 ssh 密钥登录到我的 Linux 和 FreeBSD 服务器,并为我执行特定类型的工作。 为此,我在 Raspberry PI 4 上有一个名为 autovivek 的专用用户帐户,用于 Ansible 和自定义脚本自动化。 下面是它的工作原理:
{rpi4:~}$ ssh [email protected] /path/to/taks1

在其他情况下,它会发送脚本,然后在名为 192.168.2.17 的远程服务器上执行它们。 听起来不错,对吧? 因此,当我需要进行备份和其他任务时,我会锁定服务器上的 autovivek 用户帐户,这样它就不会修改磁盘上的数据。 例如,以下是锁定用户帐户的方法:
{linux-server:~}$ sudo usermod -L -e 1 autovivek
## OR ##
{freebsd-server:~}$ sudo pw lock -n autovivek

关于锁定 Linux 和 FreeBSD 用户帐户的警示故事

然而,我很快发现一个名为 autovivek 的用户仍然可以登录到服务器并进行更改,尽管它被锁定在 Linux 和 FreeBSD 服务器上。 我愚蠢地认为它可以开箱即用。 但是,男孩,我有一个很大的惊喜。

之上 close 检查 autobox(RPi 4 计算机),我发现我在 ~/.ssh/config 文件中启用了 ssh 多路复用以加快 ssh 的速度:

Host *
	IdentitiesOnly yes
	ControlPath ~/.ssh/controlmasters/%r@%h:%p
	ControlMaster auto
	ControlPersist yes

什么是 SSH 多路复用?

SSH 多路复用只不过是通过单个 TCP 连接承载多个 SSH 会话。 换句话说,OpenSSH 为多个并发 SSH 会话重用了现有的 TCP 连接。 如果会话已在 OpenSSH 服务器上建立,则锁定或解锁的用户帐户在远程计算机上无关紧要。 它将使用 ssh 直接连接。 以下是如何确定会话是否打开:

{rpi4:~}$ ssh -O check [email protected]

这是我看到的:

Master running (pid=418156)

当然,ss 命令也会确认打开会话:
{rpi4:~}$ ss -o state established '( dport = :ssh or sport = :ssh )' | grep 192.168.2.17

会话在后台打开

tcp      0         0             192.168.2.25:ssh          192.168.2.17:22201    timer:(keepalive,1min13sec,0)                                                  
tcp      0         0             192.168.2.25:46412        192.168.2.17:ssh      timer:(keepalive,67min,0) 

在服务器端,也会在后台打开一个类似的会话:
{linux-server:~}$ ss -o state established '( dport = :ssh or sport = :ssh )' | grep 192.168.2.17

输出:

Netid                            Recv-Q                            Send-Q                                                       Local Address:Port                                                       Peer Address:Port                             Process                            
tcp                              0                                 0                                                            192.168.2.17:ssh                                                        192.168.2.25:41884                             timer:(keepalive,29min,0)    

换句话说,当 ~/.ssh/config 文件中的 ControlPersist 在客户端设置为 yes 时,ss 命令确认 ssh 在服务器的后台进行侦听。 它使 ssh 客户端和服务器之间的连接保持打开状态,以加快操作。 这就是我的问题的根本原因。 啊,谜团解开了。 从 ssh_config(5) 手册页:

  1. ControlPersist 指令指定在初始客户端连接关闭后,主连接应在后台保持打开状态(等待未来的客户端连接)。
  2. 如果设置为 no,主连接将不会被放置在后台,并且将 close 一旦初始客户端连接关闭。
  3. 可以将其设置为 yes 或 0,然后主连接将无限期地保留在后台,直到通过诸如“ssh -O exit”之类的机制被杀死或关闭。
  4. 如果设置为以秒为单位的时间,或 sshd_config(5) 中记录的任何格式的时间,则后台主连接将在指定时间内保持空闲且没有客户端连接后自动终止。

所以,这就是我解决问题的方法。

如何安全地锁定 Linux 和 FreeBSD 用户帐户并立即阻止 ssh 访问

锁定帐户是不够的。 最好停止名为“autovivek”的用户拥有的所有进程。 换句话说,我现在这样做:
{linux-server:~}$ sudo killall -STOP -u autovivek

换句话说,在 Linux 和 FreeBSD 服务器上锁定帐户的正确过程如下:
{linux-server:~}$ sudo usermod -L -e 1 autovivek # Linux
{freebsd-server:~}$ sudo pw lock -n autovivek # FreeBSD

然后在两台服务器上:
{linux-server:~}$ killall -STOP -u autovivek # STOP all processes owned by the 'autovivek' user

当然,你可以杀死它,但我只需要停止它们,然后在备份完成后,我解锁用户帐户并恢复会话:
{linux-server:~}$ sudo usermod -e -1 -U autovivek # Linux
{freebsd-server:~}$ sudo pw unlock -n autovivek # FreeBSD

同样,在两台服务器上运行 killall 命令以恢复“autovivek”用户拥有的所有进程:
{linux-server:~}$ killall -CONT -u autovivek # Resume session

SIGSTOP 和 SIGCONT 信号

killall 命令发送 -STOP (SIGSTOP) 信号以停止名为“autovivek”的用户拥有的所有进程。 类似地,-CONT (SIG) 信号用于继续(恢复)名为“autovivek”的用户所拥有的进程(如果当前已停止)。

加起来

事实上,这是一个关于锁定 Linux 和 FreeBSD 用户帐户的警示故事。 无论你多么小心,优化总会有一些副作用。 我通过多路复用启用了 ssh 速度优化,我遇到了一些惊喜。 使用 人命令 欲了解更多信息:
$ man sshd_config
$ man ssh_config
$ man ssh
$ man kill
$ man killall
$ man 7 signal

所以这让我想起了我在很多个月前开发的 Unix 帐户删除程序脚本,当时系统管理员删除了 HP-UX 上的用户帐户。 首先,它将搜索用户的所有 cron/at 作业、进程、电子邮件和用户拥有的文件。 然后归档所有文件并删除它们。