8

I run a small group of macOS machines for students (say 20) and they all need to be setup with things like homebrew and other packages and applications. I'm writing a bash script to automatically install all the things needed on each computer. Some of the commands I'll be using require being run as root, but not most of them.

I was wondering if it would be better to individually sudo each of these commands in the script, or leave sudo out of the script and sudo the entire script. I'd like to know which one will be safer (security wise), and better for my situation. I'd rather not be prompted for a password throughout the script, but I also dont want to run every line in the script as root, as it's unsafe.

5 Answers 5

7

Following the principle of least privilege, run as little as you can as root. Therefore, sudo from within the script.

Note that the first time there is a command that needs sudo, you may be prompted. (That won't be true if you applicably use NOPASSWD in /etc/sudoers which is a technique that many people will shun as also being insecure.) However, when you run sudo and provide a password, sudo will remember the success for a period of time. By default that period of time is five minutes. So if you ran "sudo echo hi", typed in your password, and then ran the script soon after that, then there would be no need for you to be prompted for a password when you run the script. More realistically, if you just run the script, you will likely just be asked to sudo once... presuming that you script takes less than give minutes to complete the remaining tasks.

I might not worry about a few echo commands, but if there is significant content that can be done without extra permissions, then, for the sake of security, I generally like to maximize how much is done with minimal elevation.

As an example of minimizing permissions, let me show you another sample scenario. Instead of:
sudo -c "sample-command >> /var/log/output.txt"

I like to use:
sample-command | sudo tee -a /var/log/output.txt >> /dev/null

By doing this, the entire command runs without sudo, and the only part that ends up having enhanced permissions is the part that needs enhanced permissions, which is the part that writes to the file.

Clearly, my goal here is to minimize how much is done elevated. Similarly, if your entire script doesn't require elevation, the preferred approach (from a security perspective) is to minimize how much is done elevated.

6
  • Welcome, 10k ;-)
    – Arjan
    Jan 19, 2018 at 7:57
  • @TOOGAM Could you do the same thing without using tee like this instead? sample-command | sudo cat >> /var/log/output.txt Or is there a difference?
    – ADJenks
    Sep 24, 2018 at 2:14
  • Hmm, I see, cat does not work...
    – ADJenks
    Sep 24, 2018 at 2:25
  • @adjenks : right. In your example, the shell realizes there is a pipe and a redirection. sample-command runs at the same time as the second thing it runs, which is "sudo cat" (the part between the pipe and the >>). Then the output of that will get redirected using the initial user account that ran the command. To handle this situation, you can place the >> inside quotes that cause >> to just be part of a single argument, as shown in the answer (where I mentioned sudo -c), or, better yet, become practiced with using tee as described by my answer.
    – TOOGAM
    Nov 17, 2018 at 2:26
  • @Flimm : Using NOPASSWD can likely cause the lack of a prompt, so you wouldn't need to worry about the timeout. The timeout can also be configured. I'm guessing there's a solid solution to whatever you are thinking may provide some grief. It isn't clear what you refer to when you say "This is not great". Can you elaborate on just what aspect may be causing difficulty for the setup you are trying to use?
    – TOOGAM
    Aug 18, 2023 at 21:26
0

Depends on what the commands are. For the command that download from the internet it’s better to not run them as root. But the other command should be ok to run as root. What I would do is separate the command in two scripts: one for non-root commands and one for root commands

Maybe I could help more if I can get the list of the commands.

4
  • zerobin.net/…
    – James C.
    Oct 2, 2017 at 21:00
  • woops, mispelled firefox, hopefully you get the idea
    – James C.
    Oct 2, 2017 at 21:01
  • Is the script in order? Oct 3, 2017 at 17:09
  • 1
    "For the command that download from the internet it’s better to not run them as root" - it's best NOT to run them at all, just pasting & running random commands is a terrible idea in general. At least look up their man pages and understand what you're trying to do first, then run only if it looks safe.
    – Xen2050
    Mar 1, 2019 at 2:59
0

Usually, (I assume) you would want the script to be treated just like any other command/application/utility. In which case, you typically wouldn't be prompted for a password to escalate your privileges; you'd just be denied, and receive an error. Something like:
Permission denied, or Operation not permitted.

But, you specifically mentioned that you:
"..don't want to run every line in the script as root.."
So I don't really see an alternative to explicitly, and exclusively invoking sudo in / from the specific lines of code where it's relevant.

You also mentioned that you'd:
"..rather not be prompted for a password throughout the script.."
And chances are you won't. You won't be prompted every time sudo is invoked unless a significant amount of time passes between operations.

0

I have used this throughout my scripts when I wanted just some commands to be executed as root and others not

echo $admpass | sudo -S *COMMAND*
1
  • It's a very bad idea to store passwords in the shell script directly. This is reasonable if and only if $admpass came from user input. Jun 14, 2018 at 17:57
0

Here's one solution: run the script as root using sudo, and run any commands that don't require elevated privileges as the original user using sudo -u $SUDO_USER <command>.

Here's an example script example.sh:

#!/bin/bash

if [ "$(whoami)" != "root" ] ; then
    echo "Run this script with sudo" >&2
    exit 1
fi

sudo -u "${SUDO_USER:-$USER}" this_command_run_as_user
this_command_run_as_root
this_command2_run_as_root

You would run it like this:

sudo ./example.sh

The advantage of doing it this way is that the user's password will only be requested at most one time at the start of the script. You don't need to worry about timeouts for sudo.

1
  • The question said "I also dont want to run every line in the script as root, as it's unsafe." In this example, this_command_run_as_user is run as a user account, but the command in the script file is "sudo -u "${SUDO_USER:-$USER}" this_command_run_as_user" and that line, like every other line in the script file, is being run as root. Better to just run as root whatever is needed as root. If passwords are an issue, /etc/sudoers can have :NOPASSWD applied to an account or a group. A specialized account could be made if needed, & an ssh key forcing a specific command could be potentially helpful
    – TOOGAM
    Aug 20, 2023 at 6:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .