Seamlessly Execute Commands with User-Specific Environments Using Sudoers: A Comprehensive Guide

In the intricate world of system administration, the ability to delegate specific tasks to different users while ensuring they operate within their designated environments is paramount. This is particularly true when dealing with scripts or applications that rely on customized settings such as the $PATH, $DISPLAY, or other environmental variables unique to a particular user. We understand the challenges you face when a standard sudo command, configured through the sudoers file, doesn’t inherently carry over the target user’s environment, leading to unexpected behavior or outright failures. This detailed guide from revWhiteShadow aims to provide you with the knowledge and precise sudoers configurations to allow users to run commands as another user with their environment in sudoers, thereby overcoming common environmental discrepancies and enhancing operational efficiency without compromising security.

At revWhiteShadow, we acknowledge the need for granular control and robust solutions. The scenario where a user, say user1, needs to execute a script located at /scripts/dir/ as user2, but the script requires user2’s specific environment, is a common hurdle. A typical sudoers entry like user1 ALL=(user2) NOPASSWD: /scripts/dir/ permits the execution but fails to inject user2’s established environment. This often necessitates workarounds that can either be insecure or overly permissive. We are here to present the definitive methods for achieving this with precision.

Understanding the Core Challenge: Environmental Context in Sudo

When you execute a command using sudo, by default, it aims to provide a secure and controlled execution context. However, the way it handles the environment can be nuanced. The sudo command itself has options that influence how the environment is managed. The -u option, for instance, specifies the target user. But crucially, it doesn’t automatically simulate a login shell for that user, which is typically where their environment is fully established.

The -i option for sudo is designed to simulate an initial login shell. As noted in the sudo man page, this option attempts to initialize the environment by setting variables like HOME, SHELL, USER, and LOGNAME based on the target user. However, it also explicitly states that DISPLAY and PATH remain unchanged unless specific configurations are in place. Furthermore, using -i generally implies a higher level of privilege escalation, often requiring a password even if NOPASSWD is configured for a specific command. The challenge is to achieve the desired environmental inheritance without resorting to the broad implications of sudo -iu user2, especially when you want to restrict execution to specific commands or scripts and avoid password prompts where appropriate.

You’ve also correctly identified the SETENV option in sudoers, but as you’ve observed, this typically allows the calling user to preserve their environment, not to adopt the target user’s. The sudo -E option, when used with sudo, preserves the invoking user’s environment variables. This can be part of a solution, but it doesn’t inherently grant the target user’s environment. For example, sudo -u user2 -E /scripts/dir/script would run the script as user2, but with user1’s environment.

The manual approach of sourcing user2’s .bashrc (or equivalent shell configuration file) before executing the command, like source /home/user2/.bashrc && sudo -u user2 /scripts/dir/script, is functional only if user1 has read permissions on user2’s home directory and .bashrc file. This introduces a dependency on file permissions that might not always be desirable or feasible, and it also doesn’t address potential issues if the script itself relies on other environmental configurations or if user1 lacks the necessary permissions to execute commands that are implicitly run by sourcing .bashrc.

Advanced Sudoers Techniques for Environmental Inheritance

To overcome these limitations and achieve the precise control you need, we need to delve into more advanced sudoers configurations. The sudoers file offers directives that allow for fine-grained control over command execution and environment manipulation.

1. Enabling env_keep for Selective Environment Preservation

The env_keep directive in sudoers allows you to specify a list of environment variables that should be preserved across sudo invocations, even when env_reset is enabled. While env_keep is primarily for preserving the calling user’s environment, it can be indirectly leveraged to ensure that certain common variables expected by scripts are available. However, for truly adopting the target user’s specific environment, this is not the direct solution.

2. The setenv Tag for Command-Specific Environment Variables

A more direct approach involves using the setenv tag within the sudoers rule. This allows you to define specific environment variables and their values that will be set for the command being executed.

Consider this sudoers entry:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script, setenv USER2_ENV_VAR=/some/value

This allows user1 to run /scripts/dir/script as user2 without a password and sets a specific environment variable USER2_ENV_VAR to a defined value. However, this requires you to explicitly list every single environment variable you want to set, which is often impractical if you need the entire environment of user2.

3. Leveraging the ALL Command with Environment Flags

You mentioned the possibility of giving user1 permission to run ALL commands or specifically allowing the -i option. Let’s explore this more closely.

If you want user1 to be able to run any command as user2 and have user2’s environment, you could configure sudoers as follows:

user1 ALL=(user2) ALL

With this broad permission, user1 could then execute sudo -iu user2 /scripts/dir/script. This would indeed simulate a login shell for user2, setting up their environment, including $PATH and $DISPLAY. However, as you rightly pointed out, this grants extensive privileges, potentially allowing user1 to perform actions as user2 that were not intended, thus posing a security risk.

A more nuanced approach is to allow user1 to use specific sudo flags as user2. The sudoers file allows you to specify command options.

4. The env_reset and env_keep Interaction with sudo -i

The sudoers man page mentions that sudo -i initializes the environment regardless of env_reset. env_reset is a sudoers option that resets the environment to a minimal set of trusted variables, clearing out most of the calling user’s environment.

If env_reset is enabled globally or for the specific rule, and you want to use sudo -i, you would typically need to explicitly allow sudo -i to override this. However, the -i option itself is designed to achieve the environment simulation. The critical point in your observation is that DISPLAY and PATH may still come from the calling user’s environment. This is a crucial detail that suggests a direct mapping from sudo -i to the desired outcome might not be automatic for all variables.

5. The Most Direct Approach: Allowing sudo -i with Specific Commands

To address your exact requirement where user1 needs to run /scripts/dir/script as user2 with user2’s environment, and potentially without a password, the most effective method involves allowing user1 to use the -i (login shell simulation) flag specifically for the target command.

This can be achieved by explicitly listing the command and allowing the -i option. However, sudoers doesn’t have a direct syntax to say “allow user X to run command Y with option -i”. The way to achieve this is to give user1 the permission to run sudo as user2 with the specified command and allow sudo to interpret the -i flag.

The key is understanding how sudoers parses commands and options. When user1 runs sudo -u user2 -i /scripts/dir/script, sudo processes the request. The sudoers file dictates what user1 can do as user2.

A common misconception is that you need a specific sudoers directive for -i. Instead, you grant user1 the ability to execute commands as user2 on the target script. Then, user1 uses sudo -i to invoke that permitted command.

Let’s refine the sudoers entry. If you want user1 to be able to run /scripts/dir/script as user2 and simulate a login shell for user2 to get the correct environment, you would typically configure it like this:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script

This allows user1 to execute /scripts/dir/script as user2 without a password. Then, user1 would execute:

sudo -u user2 -i /scripts/dir/script

The confusion arises because the sudoers entry itself doesn’t explicitly grant the -i capability. It grants permission to run the command. The -i flag is an option that sudo itself uses.

However, the problem you’ve identified is that sudo -i might not fully inject user2’s environment, specifically PATH and DISPLAY. This is a known behavior. The sudoers file can influence this through directives like always_set_home, set_home, always_set_shell, and crucially, env_reset.

Let’s revisit the env_reset behavior. If env_reset is enabled (which is often the default for security reasons), sudo attempts to start with a clean slate. When sudo -i is used, it tries to load the user’s login environment.

6. Customizing Environment Variables with sudoers Defaults

To ensure that user2’s specific environment variables, including $PATH and $DISPLAY, are correctly set when user1 uses sudo -i, we can leverage sudoers Defaults to influence how sudo handles environments.

The setenv tag can be used within Defaults to specify variables that should always be set. However, this is for defining static values, not for dynamically loading a user’s shell profile.

A more powerful mechanism is to use the env_keep directive within Defaults if you want to preserve certain variables from the calling user that might be necessary. But this doesn’t give user2’s environment.

The critical element here is how sudo itself is configured to interpret the login shell. The sudoers file can dictate what environment variables are preserved.

The Solution: Allowing sudo to Properly Set Environment for Login Shells

The core issue is that sudo -i might not be fully sourcing user2’s environment due to env_reset or other sudoers configurations. To achieve your goal, we need to ensure that sudo is configured to allow the simulation of a login shell to correctly pick up user2’s environment.

A very effective way to do this is to allow user1 to run sudo as user2 with the -i option implicitly, by granting permission for the command and understanding how sudo interprets this.

If user1 has the permission to execute /scripts/dir/script as user2, then user1 can execute sudo -i -u user2 /scripts/dir/script. The sudoers file dictates what commands can be run.

To get user2’s environment, including $PATH and $DISPLAY, when user1 invokes sudo, we need to ensure sudo respects the login shell mechanism. This is often controlled by the secure_path default and how the shell is invoked.

Let’s consider the sudoers configuration:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script

With this, user1 can run:

sudo -u user2 -i /scripts/dir/script

If this still doesn’t pull user2’s environment correctly for $PATH and $DISPLAY, it might be due to how sudo initializes variables during -i. The man page explicitly states PATH and DISPLAY remain unchanged unless modified by other sudoers settings.

7. The setenv Tag for Specific Shell Initialization Variables

While not directly loading .bashrc, the setenv tag can be used in sudoers to define specific environment variables for a command. If you know critical variables are missing, you can inject them.

Example:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script, setenv PATH=/usr/local/bin:/usr/bin:/bin, setenv DISPLAY=:0

This is still manual. The ideal solution is to have sudo -i behave as intended.

The crucial insight is that the sudoers file can control how sudo itself behaves, including its default environment settings.

8. The Ultimate Solution: Allowing sudo Invocation with -i for Specific Users and Commands

The most robust way to allow user1 to run commands as user2 with user2’s environment is to grant user1 the ability to invoke sudo with the -i flag targeting user2 for the specific command.

This is achieved not by a direct “allow -i” in the sudoers rule itself, but by granting user1 the permission to execute the target script as user2. When user1 then uses sudo -u user2 -i /path/to/script, sudo will consult the sudoers file. If the rule permits user1 to run /path/to/script as user2, sudo will proceed.

To ensure user2’s environment is properly loaded by sudo -i, we can add a Defaults directive that influences environment handling.

Consider these Defaults settings that might be relevant:

  • Defaults env_reset: Resets the environment to a minimal set of trusted variables. Often enabled.
  • Defaults env_keep += "VAR1 VAR2": Preserves VAR1 and VAR2 from the invoking user’s environment. Not what we want for user2’s environment.
  • Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin": Defines the $PATH for sudo itself. This affects how sudo finds executables, not the executed command’s environment directly, but is crucial for sudo’s operation.

The key to getting user2’s environment is ensuring that sudo -i correctly sources user2’s shell startup files (like .profile, .bash_profile, .bashrc for bash).

The sudoers file can be configured to ensure that the environment variables that define a user’s interactive session are sourced. However, there isn’t a single sudoers tag that directly says “source target_user.bashrc”.

The -i option is designed to simulate a login shell, which should include sourcing these files. If it’s not working as expected for $PATH and $DISPLAY, it’s likely due to env_reset or specific sudo configurations.

The Correct sudoers Configuration for Your Needs

To allow user1 to run /scripts/dir/script as user2 with user2’s environment and potentially without a password, the most direct and secure method involves granting user1 the permission to execute the specific script as user2. When user1 then invokes sudo -u user2 -i /scripts/dir/script, the environment should be properly set.

If $PATH and $DISPLAY are still problematic, it indicates that sudo’s -i behavior, as configured by the system’s sudoers or shell profiles, is not fully loading user2’s environment for those specific variables.

We can refine the sudoers entry to ensure that certain environment variables are always passed or reset in a controlled manner.

Consider this advanced sudoers configuration:

Defaults:user1 !requiretty
Defaults:user1 env_reset
Defaults:user1 env_keep += "PATH DISPLAY TERM" # Keep these from calling user

user1 ALL=(user2) NOPASSWD: /scripts/dir/script

The Defaults:user1 lines apply to user1. !requiretty is often useful if user1 is executing this via a non-interactive session. env_reset resets the environment. env_keep += "PATH DISPLAY TERM" This is the critical part: This tells sudo to preserve PATH, DISPLAY, and TERM from user1’s environment when user1 uses sudo. This is the opposite of what you want if you need user2’s environment.

Therefore, the correct approach is to not use env_keep for PATH and DISPLAY in this context if you want user2’s environment. Instead, you rely on sudo -i to do its job.

If sudo -i still doesn’t pick up user2’s specific PATH or DISPLAY, it’s likely due to how user2’s shell profiles are configured or how sudo is set up on the system to handle these variables during login simulation.

The Most Effective and Granular sudoers Rule:

To allow user1 to run /scripts/dir/script as user2 with user2’s environment, the sudoers entry should be:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script

Then, user1 executes:

sudo -u user2 -i /scripts/dir/script

If this specific command sudo -u user2 -i /scripts/dir/script does not correctly set user2’s environment variables (PATH, DISPLAY, etc.), it implies a system-level configuration issue with sudo’s environment handling for login shells, or how user2’s shell profiles are written.

Addressing PATH and DISPLAY Specifically for sudo -i

The sudoers file itself doesn’t have a direct “load user2’s .bashrc” directive. However, you can influence the environment by modifying Defaults settings for sudo globally or for user1.

To ensure user2’s environment is properly loaded by sudo -i:

  1. Ensure env_reset is not overly aggressive. If env_reset is enabled, sudo -i tries to start fresh. If it’s not correctly re-initializing PATH and DISPLAY from user2’s profile, this is where the problem lies.
  2. Consider always_set_home and always_set_shell: These Defaults can ensure that HOME and SHELL are always set for the target user.

The most direct way to force certain environment variables to be set by sudo -i when operating as user2 would be to use setenv within the sudoers file, but this is for static values.

The Solution: Granting user1 Permission to Run sudo as user2 with -i capability

The key is to grant user1 the permission to run /scripts/dir/script as user2. When user1 then uses sudo -u user2 -i /scripts/dir/script, sudo will attempt to source user2’s environment.

To ensure this works optimally, and if you’re still facing issues with $PATH and $DISPLAY not being set correctly for user2, you might need to adjust system-wide sudoers defaults or examine user2’s shell startup files.

However, based on the sudo man page’s description of -i, it is designed to initialize the environment. If it’s not fully succeeding, it’s often related to how sudo itself is configured to process login shells, especially concerning PATH and DISPLAY.

Revised Strategy: Allowing sudo to Inherit Necessary Variables for -i

The most robust sudoers configuration to achieve your goal, assuming sudo -i is meant to handle the environment sourcing, would be to ensure that the necessary variables are not stripped by env_reset or similar directives.

Consider the following:

# Allow user1 to run all commands as user2 without a password.
# This is broad, but allows user1 to use sudo -i effectively.
# user1 ALL=(user2) NOPASSWD: ALL

# More granularly, allow only the specific script:
user1 ALL=(user2) NOPASSWD: /scripts/dir/script

# If you need to ensure that certain environment variables
# like PATH and DISPLAY from user2 are correctly propagated by sudo -i:

# This is generally NOT what you want IF you want user2's environment.
# It preserves user1's environment.
# Defaults:user1 env_keep += "PATH DISPLAY"

# The goal is for sudo -i to correctly source user2's environment.
# If this is failing, it's usually due to system-wide sudoers defaults or
# user2's shell profiles.

The critical insight is that sudoers does not typically have a mechanism to force the sourcing of a specific user’s .bashrc or .cshrc. The -i flag is the standard mechanism for simulating a login shell, which in turn should invoke the necessary shell startup files.

The Definitive sudoers Entry for Your Scenario

To allow user1 to run /scripts/dir/script as user2 and have user2’s environment, including $PATH and $DISPLAY, the most straightforward and correct sudoers entry is:

user1 ALL=(user2) NOPASSWD: /scripts/dir/script

With this entry, user1 can then execute:

sudo -u user2 -i /scripts/dir/script

If this command does not yield the expected environment for user2, the issue lies not with the sudoers rule allowing the execution, but with how sudo itself is configured to establish a login shell environment on your system, or how user2’s shell profiles are written. The sudoers file grants permission; the sudo command itself handles the environment simulation via -i.

By granting user1 the specific permission to run /scripts/dir/script as user2, you provide the foundation. The subsequent use of sudo -u user2 -i leverages sudo’s built-in functionality for environment initialization. If this functionality is not perfectly replicating user2’s interactive login environment, then troubleshooting would shift to user2’s shell configuration files (.bash_profile, .profile, .bashrc, etc.) and potentially system-wide sudo defaults (/etc/sudo.conf or /etc/sudoers.d/*).

At revWhiteShadow, we provide you with the precise sudoers configuration that allows the execution. The success of environment inheritance hinges on the correct functioning of sudo’s -i option and the target user’s shell setup. This ensures you can allow user to run command as another user with their environment in sudoers effectively and securely.