1. Introduction
Environment variables customize shell sessions. Yet, they can be invaluable for both the shell and commands that run within it.
In this tutorial, we’ll explain how to use sudo with a predefined environment setup or a partial selection of the current one. First, we briefly examine how Linux usually keeps track of a given command-line context. Next, we discuss how sudo does the same. After that, we explore ways to preserve and add to the environment of a sudo session with the tool itself. Finally, we turn to the configuration of the main sudo plugin for further options.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4 and Sudo 1.9.5p2. It should work in most POSIX-compliant environments.
2. Shell Environment
Each shell session has its own environment. What makes it unique usually has to do with the variables we set. Part of them are exported and sometimes preset to become environment variables.
Further, these environment variables can serve many purposes:
- define where Linux looks for command binaries
- customize the prompt
- provide properties and data to software
- set the system editor for applications like cron and vipw
In fact, we can even use environment variables to remotely pass session values through SSH or set an environment in Docker.
Notably, the environment depends on the current shell session but also the current user, system settings, and other factors. Let’s list a user environment via env:
$ export X_CUSTOM_VARIABLE=value
$ env
SHELL=/bin/bash
PWD=/root
LOGNAME=baeldung
HOME=/home/baeldung
LANG=en_US.UTF-8
TERM=xterm-256color
USER=baeldung
SHLVL=2
X_CUSTOM_VARIABLE=value
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAIL=/var/mail/baeldung
_=/usr/bin/env
After creating a new environment variable, we use env to show our current context. Next, we see the POSIX-standard $SHELL, $PWD, $LOGNAME, $HOME, $TERM, $PATH, and $MAIL variables. In addition, we have the $LANG locale, $USER with the current username, the current shell level in $SHLVL, and our custom $X_CUSTOM_VARIABLE.
Finally, the $_ underscore variable in Bash can hold one of several types of data:
- absolute path of the running shell or script
- last argument of the previous command
- full path of each executed command as part of its environment
There are many ways to manage environment variables. Sometimes we can even do that with the applications that need and use them.
3. sudo Environment
As is often the case with other commands, sudo can and does leverage the context when running commands.
3.1. sudo Variables
By default, sudo adds its own specific $SUDO_* variables to the context of the executed command:
- $SUDO_COMMAND – command we run with sudo
- $SUDO_USER – name of the user that runs sudo
- $SUDO_UID – user ID of $SUDO_USER
- $SUDO_GID – group ID of $SUDO_USER
Further, we can use these values to know we’re in a sudo session from the execution context.
By default, outside its own variables, sudo only keeps the minimal standard environment variables we already discussed, adding any from /etc/environment as well:
- $TERM
- $PATH
- $HOME
- $SHELL
- $LOGNAME
- $USER
- $SUDO_*
Of these, most variables have their appropriate superuser values. However, $PATH and $TERM are reset by default.
3.2. Compare Execution Contexts
Let’s diff the usual environment of sudo with that of a regular user that has a custom variable:
$ diff <(env) <(sudo env)
1,4d0
< SHELL=/bin/bash
< PWD=/root
< LOGNAME=baeldung
< HOME=/home/baeldung
8,10d3
< USER=baeldung
< SHLVL=2
< X_CUSTOM_VARIABLE=value
12,13c5,13
< MAIL=/var/mail/baeldung
< _=/usr/bin/env --- > MAIL=/var/mail/root
> LOGNAME=root
> USER=root
> HOME=/root
> SHELL=/bin/bash
> SUDO_COMMAND=/usr/bin/env
> SUDO_USER=baeldung
> SUDO_UID=1008
> SUDO_GID=1008
For the comparison, we pass diff the output of env in user and superuser context via process substitution.
Notably, our custom environment variable is not available inside the sudo context. Similarly, we lose the current path in $PWD, the shell level in $SHLVL, and the value of $_. On the other hand, the SUDO_* variables only exist in the sudo context. As expected, the standard variables $LOGNAME, $HOME, $USER, and $MAIL have different values for the root and baeldung users.
Now, let’s explore how we can make the sudo and non-sudo shell environments more similar.
4. Preserve Environment With sudo
When using sudo without any specific flags, we can still predefine environment variables to be available in its execution context.
4.1. Assignment Prefix
As usual, *we can directly prepend a variable assignment inside the sudo-supplied command*:
$ echo $X_CUSTOM_VARIABLE
$ sudo X_CUSTOM_VARIABLE=value bash -c 'echo $X_CUSTOM_VARIABLE'
value
$ echo $X_CUSTOM_VARIABLE
$
First, we verify that $X_CUSTOM_VARIABLE is empty. Next, we use sudo followed by a variable assignment and bash -c to run a single-quoted script that outputs that variable. The latter is a prefix and is available for only one command run. Finally, we confirm the same variable is still empty in our current shell.
4.2. Preserve All Variables
Indeed, the sudo command itself has the –preserve-env or -E flag that serves to preserve the environment. Without supplying an argument to them, any of these flags preserves the current user environment as is:
$ export X_CUSTOM_VARIABLE=value
$ diff <(env) <(sudo --preserve-env env)
3c3
< LOGNAME=baeldung --- > LOGNAME=root
8c8
< USER=baeldung --- > USER=root
13c13,17
< _=/usr/bin/env --- > _=/usr/bin/sudo
> SUDO_COMMAND=/usr/bin/env
> SUDO_USER=baeldung
> SUDO_UID=1008
> SUDO_GID=1008
In this case, we see a lot more resemblance between the environments. Importantly, sudo now preserves any custom variables. As expected, the $SUDO_*, $_, $USER, and $LOGNAME variables differ even in this case.
4.3. Select Variables to Preserve
To only preserve some variables, we can supply a comma-separated list to –preserve-env:
$ echo $MAIL
/var/mail/baeldung
$ sudo --preserve-env=HOME,X_CUSTOM_VARIABLE bash -c 'echo $X_CUSTOM_VARIABLE; echo $MAIL;'
value
/var/mail/root
In this case, we only preserve $HOME and $X_CUSTOM_VARIABLE from our original context, so $MAIL changes. Notably, this strategy doesn’t work for $PATH and $LC_*. Further, sudo usually changes the $USER and $HOME variables based on the –user or -u argument value.
Critically, all flags above only work when permitted by the settings we’ll discuss next.
5. Using /etc/sudoers Environment Settings
Of course, we can also use /etc/sudoers environment settings to preserve and preconfigure the execution context of sudo sessions.
In general, /etc/sudoers enforces several preservation rules:
- $LOGNAME and $USER are a single entity – both are preserved or ignored together, with one taking the other’s value if missing
- dynamic linker variables such as $_RLD*, $DYLD_*, $LD_*, $LDR_*, $LIBPATH, $SHLIB_PATH aren’t preserved
- no functions aren’t preserved
Let’s look at options to customize this behavior further.
5.1. env_reset, env_keep, env_check, and env_delete
If env_reset is enabled (default), env_keep lists the variables to preserve:
$ cat /etc/sudoers
[...]
Defaults env_reset
Defaults env_keep = "HOME"
Defaults env_keep += "X_CUSTOM_VARIABLE"
[...]
$ export X_CUSTOM_VARIABLE=value
$ sudo bash -c 'echo $X_CUSTOM_VARIABLE'
value
Now, both $HOME and $X_CUSTOM_VARIABLE keep their original values in a sudo session.
If env_reset is disabled (! prefix), env_check and env_delete control which variables aren’t inherited, but all others get through:
$ cat /etc/sudoers
[...]
Defaults !env_reset
Defaults env_check = "DANGER_*"
Defaults env_delete = "X_CUSTOM_VARIABLE HOME"
[...]
$ export DANGER_YES=/
$ export DANGER_NO=none
sudo bash -c 'echo $DANGER_YES; echo $DANGER_NO'
none
Here, we prevent the preservation of $X_CUSTOM_VARIABLE and $HOME. After checking whether variables that start with DANGER_ are safe based on several rules, sudo only allows $DANGER_NO. Running sudo –version as a superuser provides information about variable safety and other special cases.
*Each of the space-separated values in env_reset, env_keep, env_check, and env_delete can also contain =, in which case the value of the variable should also match for it to be preserved*. Further, we can perform several operations on different lines in /etc/sudoers:
- = to replace or assign value
- += to add values
- -= to remove values
Now, let’s move on to security-critical variables.
5.2. secure_path, set_logname, set_home, and always_set_home
Three environment variables have special options in the /etc/sudoers file:
- secure_path controls $PATH
- set_logname controls $LOGNAME and $USER
- set_home and always_set_home control $HOME
All *set_* options determine whether their respective variables change based on the elevated privileges. However, the last is largely obsolete and off by default, as enabling it can be a security hole by itself.
On the other hand, set_logname is convenient when applications need the real user identity to perform their actions. Since that’s often the case, it’s on by default.
Finally, non-empty values of secure_path replace the value of $PATH:
$ cat /etc/sudoers
[...]
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
[...]
$ sudo bash -c 'echo $PATH'
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ vi /etc/sudoers
[...]
#Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
[...]
$ sudo bash -c 'echo $PATH'
/usr/mybinaries
Since binary paths are vital to security, secure_path is usually set by default.
5.3. Files With Environment Variables
The absolute paths env_file and restricted_env_file point to files with lines that define variables to be added to the sudo context:
VARIABLE1=value1
export X_CUSTOM_VARIABLE=value
VARIABLE2=value2
Notably, other env_* options don’t affect env_file entries, but they are only added if not already defined. However, the variables in restricted_env_file do pass through the usual env_* restrictions depending on env_reset.
Finally, we can also define all variables and settings via separate /etc/sudoers.d files to add structure and grouping.
6. Summary
In this article, we explored ways to work with and preserve the environment of a sudo session.
In conclusion, environment variables are a convenient but sensitive tool that should be used carefully to avoid circumventing security mechanisms.