These are all valid but they all require elevating privileges well beyond what is required. Executing the whole script with sudo while is the easiest is also a significant risk especially if it listens on any ports for incoming requests/hooks. Using the sudoers allowing all commands with or without sudo password again comes with unnecessary risk.
However we have a third option to spawn a subprocess with elevated privileges which could then be limited to allow just the required commands (for example giving it access to mkdir
but not rm
, cp
, dd
, mysqldump
, mailx
, etc. It treads the line of both worlds and elevates only what really needs to be. Now you should be careful with this as allowing say the rm
command regardless of the arguments (recursive, permissions, etc) but even still this is still safer than executing the whole script/application with full root with access to everything.
The python code:
import subprocess
cmd = 'some_command_such_as_ln_or_mkdir'
subprocess.run(cmd, stdin=True, shell=True)
This allows running just the subprocess with sudo in a shell which accepts input from stdin
so sudo can prompt for a password. If you are doing this in a automated process you can configure the sudoers to allow you to only run the min required commands without password. You should still be cautious with this but it at least is the most sane solution I have found.
The /etc/sudoers.d/$MY_USER_OR_PROGRAM_NAME
should look something like this:
$USER_PROGRAM_EXECECUTED_BY ALL = ($USER_TO_RUN_ELEVATED_COMMAND_AS) NOPASSWD: $ABSOLUTE_PATH_TO_SOME_COMMAND_SUCH_AS_LN_OR_MKDIR, $ANOTHER_ABSOLUTE_PATH_TO_SOME__OTHER_COMMAND
While you might be forced to set ($USER_TO_RUN_ELEVATED_COMMAND_AS)
as (root)
depending on your use case you should first with a more limited user. If say you need to create a directory in a directory owned and grouped by root you will need this. If say you are creating a dir in say /var/log/
and it is is owned or grouped by a user/group to allow shipping the logs to another system without needing root then you can leverage that user instead.
If you are expecting any user input that gives you even a part of the command you should be careful and look at something like shlex
for preventing shell injections: https://docs.python.org/3.5/library/shlex.html#shlex.quote
Also one last note if you do not need to read in passwords from stdin (never used interactively) then you can probably remove the stdin=True
.