The Right Way to Use sudo in Scripts

From time to time, you may need to execute some privileged commands in a shell script. While using sudo, you may want to either enter your password only once for a long running script, or execute the script without giving a password at all. This article will tell you how to do it in the right way.

Password Only Once

According to the man page, sudo supports credential caching so that user can run sudo for a period of time without authentication (password). The default caching time is 15 minutes. If you want to run a script longer than that and still keep the privilege without typing password again, you don't need to worry about anything: simply run the script with sudo.

sudo /path/to/your/script

In this case, whether each command inside the script contains sudo doesn't matter. Because the shell process is running in privileged mode, all those commands will be executed in privileged mode. Of course, using sudo by a privileged user has no side effect.

No Password

Sometimes even typing the password once is not convenient. There are several solutions to allow running a script without password.

The first solution still requires password once, and after that you can run as many scripts under sudo as you want. The idea is to trick the credential caching mechanism so the password will not expire. You can add the following line in /etc/sudoers (using visudo) to achieve that.

Defaults:YOUR_USER_NAME timestamp_timeout=-1

Any negative value of timestamp_timeout will cache the password forever (while logged in). Any positive value sets the expire time to that number of minutes. A value of 0 disable the cache, which means that you need to provide password for every sudo. If you just set Defaults rather than Defaults:YOUR_USER_NAME, this timeout will be effective for all users.

This solution is not recommended because it exposes a serious security hole. In contrast, another two methods are much safer.

The second solution is to add an exception of script in /etc/sudoers.

YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/abs/path/to/your/script

You don't need to worry about what ALL=(ALL:ALL) stands for. Those fields are rarely used in other ways. After setting up the exception, use sudo to execute your script, and no password will be asked.

If you have a lot of scripts to deal with, this seems to be inefficient. However, if those scripts share a small group of commands, you can add exceptions for each command rather than each script.

YOUR_USER_NAME ALL=(ALL:ALL) NOPASSWD:/usr/bin/apt-get update
# ...

Make sure to use absolute path of each command. Also you should execute the script normally, i.e. don't use sudo before your script.

As you can see, using sudo without a password is somewhat inconvenient. It is designed to be difficult so users can hardly misuse this powerful feature.