什么是允许root
使用 SSH 在具有权限的远程服务器上自动执行命令或脚本的好设置?
我知道(仅对某些选项含糊不清)以下选项:
- 允许通过
root
(PermitRootLogin
) 直接登录(并可能强制密钥身份验证)。 - 配置
sudo
为不需要密码(NOPASSWD
标志 insudoers
)和 TTY(requiretty
标志)。 - 配置
sudo
为在使用特定私钥进行身份验证时允许执行特定命令/脚本。 - 将脚本所有者设置为
root
并设置setuid 权限。
但首先,我不确定这些的安全后果是什么。例如,我知道允许root
登录是不受欢迎的。但我不确定,如果这不是一个过时的观点。据我了解,密码身份验证似乎很危险。使用公钥认证,直接root
登录可能没问题。对于某些选项,尤其是sudo
,我什至不确定所需的配置。虽然我可以用谷歌搜索所有这些,但我可能会错过一些安全方面的考虑,这就是我征求专家意见的原因。
请注意,我要求进行服务器端设置。执行将由程序触发,而不是由类似的工具触发ssh
,因此我不是在寻找诸如自动客户端身份验证之类的东西。
背景:ssh
在 Stack Overflow 上积极参与标签是经常出现的问题之一,是关于人们在尝试通过远程 Unix/Linux 上的 SSH 执行命令/脚本(甚至是 SFTP 服务器)时尝试的各种黑客攻击服务器服务器使用root
使用各种编程语言(C#、Java、VB.NET、Python 等)和 SSH 库(SSH.NET、JSch、Paramiko 等)的帐户。
人们尝试的实现通常尝试使用su
or sudo
。然后这些提示输入密码。因此,实现然后尝试将密码提供给命令输入。由于密码提示通常需要终端仿真su
,因此实施必须需要 PTY。这反过来又会导致进一步的麻烦,因为与终端仿真的会话经常使用交互式功能,如ANSI 转义码、分页等。所有这些都会导致更多不可靠的黑客尝试删除甚至解释 ANSI 转义码或模拟大型足够的终端以避免分页。sudo
众多例子中的几个:
- 使用 JSch 执行的“sudo”命令需要密码,即使在交互式 SSH 会话中不需要密码
- 在 Python 中使用 Paramiko 模块切换到 root 用户时获得“必须从终端运行”
- 使用 Python 在 SSH 中使用“su -l”执行命令
- 当必须切换用户时使用 JSch 到 SFTP
虽然我通常可以提供实施这些技巧的帮助,但我通常也会添加一个建议,即有比自动化sudo
/更好的方法su
。但我实际上并没有信心提供那些所谓的“更好的方法”的细节。一个相关的问题:几乎没用吗?sudo
所以我正在从超级用户的角度寻找一个规范的答案,然后可以参考并适应 Stack Overflow 的目的。
我相信对于大多数简单情况的适当解决方案[即,如果像 Puppet/Chef/CfEngine/Ansible 这样的框架是矫枉过正的],但需要对远程系统进行高级别的控制是
(a) 要求基于密钥的身份验证 (b) 锁定 SSH 可以使用的位置 - 特别是锁定 root 用户可以使用的 IP 地址 (c) 确保具有这种信任关系的机器得到适当保护。
我不相信“不赞成以 root 身份登录”,就像不赞成“以 root 身份登录做不需要 root 权限的事情”一样。拥有一个可猜测的密码可以使帐户被暴力破解,因此这是一个需要解决的问题,并且通过允许人们以 root 身份登录,他们可以犯更大范围的愚蠢错误,并做一些隐藏的可疑事情恶意活动 - 但取决于架构,这实际上可能没有意义。
这个XKCD commic指出,根据环境的不同,root 帐户是否被盗用实际上可能并不重要。
对于一般情况,最简单和最有效的解决方案可能是通过控制密钥以及在 /etc/ssh/sshd.conf 中指定适当的 AllowUsers 行来精确限制谁可以以 root 身份登录。允许普通用户但锁定 root 访问权限的适当行可能如下所示:
当然,重要的是不允许基于密码的登录,或者 root 帐户没有密码(即密码文件的密码字段中有“!”或“*”。)
正如您所假设的,如果只需要运行一个(或少量)程序,您最好设置一个具有基于密钥的身份验证的特定用户,并允许对所需命令进行适当的 sudo 访问。
当然,可以做很多事情来进一步“锁定”访问,具体取决于数据的值 - selinux、远程日志记录、有限的 shell、时间限制、登录时立即通知,像fail2ban这样的主动日志监控[除了我认为是非可选的网络限制]都可以成为解决方案的一部分。就是说,如果您只是控制一个可以轻松被吹走和重新创建的系统,那么其中大部分可能是矫枉过正的。
请记住,安全性是分层建立的,为了能够获得 root 访问权限,一个帐户应该需要通过多个层。锁定访问、SSH 私钥、防火墙、时间限制 [和最少访问原则,即只提供对所需内容的访问,不再提供对日志、备份的访问] 作为良好安全性的一部分应该一起发挥作用。
附加 - SUDO 访问
Sudo 是一种允许普通用户以提升的访问权限运行某些命令的机制,并且非常灵活且范围多样。虽然 sudo 的概要在这里并不合适(但如果您在大多数发行版中键入man sudo ,则有据可查,适当的步骤可能是 -
编辑 /etc/sudoers - 大多数 Linux 变体都有一个特殊的程序来执行此操作,称为“visudo”,需要以 root 身份运行,大致相当于使用系统编辑器编辑 /etc/sudoers(这是另一种方法这 - 虽然可能会出现)
添加/更改适当的行以让给定的用户做特定的事情。例如,如果您希望它们能够挂载目录而无需输入密码,您可以输入如下行:
然后运行此命令,适当的用户将运行类似
您可以为多个命令列出多行,使用组而不是使用 - sudoers 是一个相当灵活的子系统。在许多发行版中,还可以将带有命令的文件添加到 /etc/sudoers.d 等子目录中
以下是来自 Unix Stackexchange 帖子
How to remote execute ssh command a sudo command without password的回答。
此方法允许服务器管理员允许您的帐户执行一个命令,
sudo
而无需指定密码。该命令可能是对您的脚本的调用,并且仅在您的帐户下运行时才允许使用。由于允许的命令是完全指定的,包括参数,我相信这种方法非常安全。我在类似情况下的设置是
/home/blesseduser/.ssh/authorized_keys
:在该脚本中,我对
SSH_ORIGINAL_COMMAND
变量进行了一些清理(加上一些审计)并提取了用户想要运行的命令。所有允许的命令都在用户/home/blesseduser/bin
中作为符号链接/usr/local/bin/sudo-runner
:符号链接由
sudoers
文件中的脚本生成。当不存在命令时,bin
将列出其目录的内容。如果您不限制端口转发,可能会发生坏事。一般注意事项
无论何时使用 SSH,都应避免密码验证,即/etc/ssh/sshd_config文件应包含以下行:
However, if one - for some reason - has to use password authentication, one should use established, well known and tested tools, like sshpass. Do not start to pipe around passwords by yourself.
If using pubkey authentication it does not make sense to protect the private key by a passphrase, if the passphrase is in turn stored inside a config file or alike. If an attacker is able to gain filesystem read access to steal the private key file, he will also be able to steal the config file.
All commands that can run with user privileges, should run with user instead of root privileges.
The used programming language will not be considered in this answer, since there is no difference between Python's
subprocess.call
, Java'sjava.lang.Runtime.exec
or a subshell environment inside a shell script with regards to security.Further hardening the remote host against external attackers by configuring a firewall, putting IDS/IPS systems in place and the like will also not be considered, since it is out of scope.
That said, let us consider different scenarios:
Running Commands of Which a Finite Subset Requires Root Privileges
One should use a separate user (
adduser --shell /bin/rbash --disabled-password remcmdexec
will create a user with a restricted shell, not able to do local but only remote logins, seeman adduser
andman rbash
) in combination with a sudoers file that allows this user to only run the required, finite set of commands as root (seeman sudoers
) on the remote host:Requiring a password to run these commands with
sudo
does not make sense, since local login was disabled (--disabled-password
parameter) and an attacker who was able to steal the key file will also be able to steel the required password (see answer's first section).The authorized_keys file should contain further restrictions to prevent e.g. port forwarding, see
man sshd
:It should further be owned by root and being read- but not writable by the remcmdexec user, to prevent removal of SSH restrictions:
Invoke e.g.
ssh remcmdexec@remhost sudo /usr/bin/systemctl reload some.service
for a command that requires root privileges. For all other commands skipsudo
.Running Commands of Which a Nonfinite but Proper Subset Requires Root Privileges
The same setup as presented at the answer's previous section can be used, but the sudoers file needs to be adapted:
This is, because remcmdexec finally needs to gain root privileges. Understand that an attacker who is able to login as remcmdexec is now able to remove each and every restriction put in place on the remote host, no matter how intricately the way to achieve root privileges was designed. Therefore all those restrictions are futile in regards to security (A willing attacker). However, they are not futile in regards to safety (System failures).
Running a Nonfinite Set of Commands of Which All Require Root Privileges
It does no longer make sense to use
sudo
. Instead login in as a user with root privileges to run a command:ssh root@remhost /usr/bin/somecmd
Therefore the following line has to be present at the /etc/ssh/sshd_config file:
However, keep the restrictions inside the authorized_keys file to preserves some basic safety.
Here's an answer about the security considerations, which I think haven't been addressed in the other answers.
There are multiple parts to this: allowing the execution of a single script or command with elevated privileges (root), and using SSH. These are not necessarily dependent.
This will allow anyone to have full root privileges (not restricted to your single command/script). It will also allow anyone to try to break into your system remotely, by trying passwords etc.
This will allow any user to have full root privileges, as long as he is logged in. In terms of security it's not much better than allowing root login, though there'll be less automated attempts to break into other user accounts.
I am not sure how this would be implemented - sudo doesn't know anything about SSH keys, at least the sudo variants I am familiar with.
Configuring sudo to only allow execution of specfic commands/scripts is much better from a security point of view (because it's more restrictive).
This will allow any user to execute this script as root. You can't restrict this to particular users, and setuid bits have their own potential security weaknesses.
In the end, I don't think there's a single canonical answer - the best solution depends on your circumstances and requirements. So, like in all security-related things, you first sit down and spell out the requirements: How permissive and flexible do you want to be? What is the actual use case? How tightly do you need to tie the system down? Etc.
That said, let me add a very restrictive alternative you haven't mentioned:
Create a specific user account that is only used to execute that particular script/command. Only allow SSH login into this user with a key pair (disable passwords). Configure sudo to allow this user to execute the particular/script command as root.
That has the following security consequences:
External hackers can't crack the password of the specific account using brute force.
Anyone gaining access to this account will only be able to execute the single script/command.
Other users don't get elevated privileges through this construction.
No setuid weaknesses.
Ansible是自动化和远程主机上的最佳工具。使用 Ansible 的可用方法可以在远程机器上
--become & --become_method
以超级用户 (root) 身份执行命令,以通过 sudo 切换到 root,而无需为 sudo 启用允许 root 登录和 NOPASSWD。此外,不需要在客户端主机上进行任何安装——唯一的要求是远程主机应该支持 Python >= 2.7。
AFAIK Ansible 有两种访问方法,一种是使用 SSH 和 Paramiko。