6

Is it considered good or bad practice to use the sudo command inside a shell script? One advantage is that if the user runs the script as non-root, she or he will be asked for password on demand rather than the script failing. On the other hand, if the user has recently run a command with sudo, the script will implicitly run commands as root which may not be what the user expects.

Here is an example:

$ cat foo1
#!/bin/sh
sudo bar #implicit sudo
$ ./foo1

$ cat foo2
#!/bin/sh
bar
$ sudo ./foo2 #explicit sudo
  • 1
    It is considered bad practice. su and sudo in a shell script sudo displays typed password in bash script – Bobby Jul 15 '12 at 18:24
  • OK, I'm convinced. If you turn your comment into a reply I can accept it. – August Karlstrom Jul 15 '12 at 18:46
  • I view using sudo for an entire script (ie every command within the script running as root) to be a terrible idea. There is a reason sudoedit won't let you edit regular files as root. You can break your system and lock yourself out pretty quickly with a poorly thought out script, it only takes a chmod -R or chown -R that ends up targeting your home folder to make things go bad fast. – dragon788 Nov 27 '17 at 20:12
7

Using sudo is always a good practice. However there are ways to make the use of sudo better. One methods would be to explicitly allow a specific command to run with elevated privileges.

The following would allow only people in the "users" group to execute the command foo1 without a password.

%users ALL=(ALL) NOPASSWD: /full/path/to/foo1

However it would not allow the execution of foo2 in your above example unless a user entered the correct password.

In addition it is often better to configure sudo to require the user's password and not the root password (I am forgetting the configuration option at this moment), and to not have any entries which can allow for users to escalate their privileges, such as:

ALL ALL=(ALL) ALL

or

%users ALL=(ALL) ALL

The user of a wheel group or a similar group for escalation of any command is a good practice. In the end it is best for the root password to be locked away in a safe, never to be used by anyone (ever) unless the stinky stuff hits the fan.

  • 2
    If used in scripts requiretty should be off, too. In some distributions requiretty is set as default. – Nils Jul 15 '12 at 20:52
0

/brief opinion

Personally I believe if you aren't looking at the script before you run it, whatever side effects that happen are mostly your fault (commands running with sudo that don't prompt you for example), but at the same time, I know it can be hard to parse and grok an entire script every time. Overall I prefer a hybrid strategy where I can balance convenience and security.

/end opinion

Keep in mind you can always run sudo -k before calling a script to require the first implicit sudo call to prompt for your password, though unless it also is run after every sudo command inside the script it will ONLY prompt you for the very first call to sudo.

There are a few ways to accomplish a safe, sane script using sudo only when necessary, some more icky/ill-advised than others. This post outlines a few examples/options that I will expand upon further. https://bitmingw.com/2017/01/22/use-sudo-in-scripts/

You can run the whole script with sudo which as you described is "explicit", but this also means ALL the commands within the script run as root, and if it isn't well written or you forgot that $USER might change inside the script to root and you instead needed to use $SUDO_USER then you could end up in a world of hurt. I've accidentally done this in the past and weird and terrible things happened and then you (and I) end up guarding your scripts with if [ $EUID -eq 0 ]; then echo "Don't run as root!"; fi or the opposite -gt 0 and you have to remember to put one of the guards in every script you write (or learn configuration management tools like SaltStack/Puppet/Chef that can automate some of this for you).

sudo somescript.sh

The option I prefer to use is to run TEMPORARILY run sudo with an infinite cache time so no other sudo commands run by you require a re-prompt (or possibly anybody depending on how you set it up). Ideally you would put a properly automated and tested function (or include your "cache_sudo.sh" script) early in your scripts and then remove the infinite timeout enabling sudoers.d file as soon as the script exits (killed/finished/error) using trap and then sudo -k to expire the session/token after removing the file. See this answer for a example of testing and add the file only if valid.

This is the manual version, don't put this into your script.

sudo visudo -f /etc/sudoers.d/infinite_cache_myuser
#Add next line to the file
Defaults:YOUR_USER_NAME timestamp_timeout=-1

The benefits of the infinite cache is within your script you can elevate ONLY the commands that require root with sudo, while not having to "downgrade" ALL the other commands using su $MY_REGULAR_USER some_command or sudo -u $MY_REGULAR_USER some_command for EVERY SINGLE command. (I really dislike pointlessly repeated code to drop privileges if there is a less painful and not totally insecure way to write it to only elevate when necessary).

One way to lessen the repeated code would be define a short command "prefix" that adds sudo or su $MY_USER depending on whether the script will be run with sudo ./myscript.sh or ./myscript.sh with sudo inside.

You could write a sudoers rule to allow executing the target script with sudo and no password prompt but I think this is just as bad an idea as the first option, it only helps slightly if you want to run sudo from a cron job that runs as a non-root user but needs to alter something that requires root or another user, though you'll need to read man sudoers to learn the syntax for allowing a user to impersonate another user.

# Customize line below and add to /etc/sudoers or /etc/sudoers.d/my_script_runner
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/abs/path/to/your/script

You can also allow passwordless sudo for only the commands that require it, which allows you to run the script as non-root and still access those commands.

YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get update
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get upgrade
YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/updatedb

This option is probably my second choice behind the infinite cache trick. The downside is you are editing the sudoers file every time you find a new command that needs root, rather than just being able to add sudo in front of the command in your script. The upside is you are only allowing passwordless sudo when necessary, and you can still require a password for other sudo commands thus staying much safer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.