What is a good setup that allows automatic execution of a command or a script on a remote server with root
privileges using SSH?
I'm aware (only vaguely for some the options) of the following options:
- Allowing a direct login by
root
(PermitRootLogin
) (and possibly forcing key authentication). - Configuring
sudo
not to require a password (NOPASSWD
flag insudoers
) and TTY (requiretty
flag). - Configuring
sudo
to allow an execution of specific commands/scripts, when authenticated with a specific private key. - Setting the script owner as
root
and setting setuid permission.
But first, I'm not sure what are security consequences of these. For example I know that allowing root
login is frowned upon. But I'm not sure, if that is not an obsolete point of view. From what I've understood, it looks like a password authentication is the danger. With public key authentication, the direct root
login might be ok. And for some of the options, particularly the sudo
, I'm not sure even about the configuration needed. While I am able to google all that, there might be security considerations that I may miss, that's why I'm asking for experts' opinion.
Note, that I'm asking for a server-side setup. The execution will be triggered by a program, not a tool like ssh
, so I'm not looking for things like automatic client authentication.
Background: Being active in ssh
tag on Stack Overflow, one of frequent questions that come up, are about various hacks that people attempt, while trying to execute a command/script (or even an SFTP server) over an SSH on a remote Unix/Linux server server using a root
account using various programming languages (C#, Java, VB.NET, Python, etc.) and SSH libraries (SSH.NET, JSch, Paramiko, etc.).
The implementations, that the people attempt, usually try using su
or sudo
. These then prompt for a password. So the implementations then try to feed the password to the command input. As su
and sudo
often require terminal emulation for the password prompt, the implementation have to require PTY. Which in turn causes further troubles, as sessions with the terminal emulation often employ interactive features, like ANSI escape codes, pagination, etc. All these lead to loads of further unreliable hacks that attempt to remove or even interpret the ANSI escape codes or simulate large enough terminal to avoid pagination.
Few examples out of many:
- “sudo” command executed with JSch requires password, even when the password is not required in an interactive SSH session
- Getting “must be run from a terminal” when switching to root user using Paramiko module in Python
- Executing command using “su -l” in SSH using Python
- Using JSch to SFTP when one must also switch user
While I usually can provide a help with implementing these hacks, I also usually add a suggestion that there are better ways than automating sudo
/su
. But I'm not actually confident about providing details of those purported "better ways". A related question: Is sudo
almost useless?
So I'm looking for a canonical answer from a Super User perspective, which can then be referred to and adapted for Stack Overflow purposes.
Best Answer
General Considerations
Whenever using SSH, password authentication should be avoided, i.e. the /etc/ssh/sshd_config file should contain the following lines:
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.