Unix/Linux safe remote commands

Do you need to execute some commands from batch scripts on a remote host but don’t want to allow full shell access? For a single command, you can use sshd’s ForceCommand, but it allows only one command per account. This text explains how you can execute safe, remote, limited multiple commands.

The trick :

  • Create a special, unique, passwordless user for remote commands, such as “sudo_lover”.
  • ForceCommand‘ runs a Python script named “use_sudo,” which acts like a safe version of “sudo $SSH_ORIGINAL_COMMAND”. You can configure allowed commands with sudo.
  • use_sudo‘ logs commands (auth.log), making it easy to add a command by almost a copy and paste (for example, configuring rsync without the log would be almost impossible).

One drawback is the difficulty in redirecting STDOUT/STDERR. To redirect STDOUT, I use a second program named “out_to,” which takes the file to redirect to and the command to execute.

cat use_sudo
#!/usr/bin/python3
import os
import shlex
import logging
import logging.handlers
from logging.handlers import SysLogHandler

# logger configuration : auth.info
syslogHandler = logging.handlers.SysLogHandler(address='/dev/log', facility="auth")
formatter = logging.Formatter('use_sudo: %(levelname)s - %(message)s')
syslogHandler.setFormatter(formatter)

logger = logging.getLogger('use_sudo')
logger.setLevel(logging.INFO)
logger.addHandler(syslogHandler)

command_from_env = os.environ.get("SSH_ORIGINAL_COMMAND")
if(not command_from_env):
    print("SSH_ORIGINAL_COMMAND is undefined.")
    exit(1)
command_with_arguments = shlex.split(command_from_env)
logger.info(str(command_with_arguments))

command_for_sudo = [f"/usr/bin/sudo -n {command_with_arguments[0]} ...",'-n'] + command_with_arguments
os.execv("/usr/bin/sudo", command_for_sudo)

cat out_to
#!/usr/bin/python3
import os
import sys
import subprocess

arguments = sys.argv
outfile=arguments[1]
command = arguments[2:]
with open(outfile, 'w') as outfile_h:
    try:
        subprocess.run(command, stdin=sys.stdin, stdout=outfile_h, stderr=sys.stderr, check=True)
    except subprocess.CalledProcessError as e:
        print(f"Error while executing : {e}")