Run only parts of a script as sudo, entering password only once

I am writing a script (actually a combination of scripts and makefile) that installs external dependencies: some apt-get commands, some git cloning, building, installing, adding users to groups, ...

Some of the operations in these scripts require superuser permissions, some don't.

Until now I have run the entire make process with sudo, but it has some drawbacks:

  • git repos I clone get root as owner, which means I can't modify them afterwards without sudo or chown
  • the scripts that add users to groups don't know which user to add since whoami returns root

What is the best way of running as superuser only the commands that require it? Ideally the process would still require me to enter my sudo password, but only once at the very beginning of the install process. It would then forget it at the very end, but keep it all the time until then (it can take several hours).

The solutions I have found online include:

  • sudo -v at the begninning of the script, but if I understand correctly this times out. My script could be running for a couple of hours
  • running the script with sudo, but the commands that do not need superuser with sudo -u $(logname) <command>. This is what I do now, but it feels like it should be the other way around.

Ideally, I would like my script to:

  1. ask for superuser credentials
  2. run normal commands as the logged in user
  3. run sudo commands with the credentials entered at step 1
  4. sudo -k to close the superuser session

Since you have sudo access, create a sudoers file for yourself, then delete it when the script is done:

# grant this user access to the sudo commands without passwords
# add all required cmds to the CMDS alias
sudo tee /etc/sudoers.d/$USER <<END
$USER $(hostname) = NOPASSWD: /usr/bin/apt-get, /usr/sbin/adduser, /bin/rm, ...
END

# your script goes here
sudo apt-get install ...
git clone ...
sudo adduser group2 $USER
sudo adduser group1 $USER
: ...

# then, remove the sudo access
sudo /bin/rm /etc/sudoers.d/$USER
sudo -k

One way, that I wouldn't generally recommend, is to read in the password yourself, and use sudo's -S option to pass the password as and when needed:

#! /bin/bash
IFS= read -rsp 'Enter your password: ' password
git clone ...
sudo -S apt-get install foo -y <<<"$password"

From man sudo:

 -S, --stdin
             Write the prompt to the standard error and read the password
             from the standard input instead of using the terminal device.
             The password must be followed by a newline character.