Jenkins normally runs shell commands as the jenkins user. However, some server-maintenance tasks require root privileges—for example, cleaning APT caches, removing old packages, or managing system files.

A common but unsafe approach is to give the Jenkins user unrestricted sudo access:

jenkins ALL=(ALL) NOPASSWD: ALL

This allows Jenkins jobs to execute arbitrary commands as root.

A much safer approach is to allow Jenkins to run only one specific maintenance script as root.

Approach: Allow Jenkins to Run Only One Script with sudo

In this example, we will create a cleanup script at:

/var/www/cleanup.sh

Jenkins will be allowed to execute this script as root, but it will not receive general root access.

1. Create the Root-Level Shell Script

Create the script on the server:

sudo nano /var/www/cleanup.sh

For example:

#!/bin/bash

set -e

echo "Running cleanup as:"
whoami

echo "------------ Check space before cleanup"
df -h

echo "------------ Clean the APT Cache"

du -sh /var/cache/apt/archives
apt-get clean
du -sh /var/cache/apt/archives

echo "------------ Remove Old Kernels"

apt-get autoremove -y

echo "------------ Check space after cleanup"
df -h

The important part is that the script contains the commands that require root privileges.

2. Set the Script Ownership and Permissions

Make the script executable:

sudo chmod 750 /var/www/cleanup.sh

Set the owner to root:

sudo chown root:root /var/www/cleanup.sh

You can verify the permissions:

ls -l /var/www/cleanup.sh

You should see something similar to:

-rwxr-x--- 1 root root ... /var/www/cleanup.sh

This prevents the Jenkins user from modifying the script itself.

That is important because if Jenkins could modify the script, restricting sudo to that script would provide little security benefit.

3. Create a Dedicated Sudoers Configuration

Instead of modifying the main /etc/sudoers file, create a dedicated configuration file:

sudo visudo -f /etc/sudoers.d/jenkins-cleanup

Add:

jenkins ALL=(root) NOPASSWD: /var/www/cleanup.sh

This rule means:

  • jenkins — applies to the Jenkins user
  • ALL — applies on the current host
  • (root) — the command can run as root
  • NOPASSWD — Jenkins does not need to provide a password
  • /var/www/cleanup.sh — Jenkins can run only this specific command

Save and exit.

Using visudo is recommended because it validates the sudoers syntax before installing the configuration.

4. Test the Sudo Permission

Before configuring Jenkins, test the command as the jenkins user:

sudo -u jenkins sudo /var/www/cleanup.sh

You can also run it with Bash tracing:

sudo -u jenkins sudo bash -x /var/www/cleanup.sh

You should see:

Running cleanup as:
root

This confirms that the script is actually being executed with root privileges.

Note: Running sudo -u jenkins bash -x /var/www/cleanup.sh by itself does not test the sudo permission. It only runs the script as the jenkins user. To test the root-level permission, use sudo -u jenkins sudo /var/www/cleanup.sh.

5. Configure Jenkins

In your Jenkins job, use an Execute shell build step:

#!/bin/bash

set -e

echo "Starting server cleanup..."

sudo /var/www/cleanup.sh

echo "Server cleanup completed."

Jenkins will execute:

sudo /var/www/cleanup.sh

The sudoers rule allows this command to run without requiring a password.

6. Verify That Jenkins Does Not Have General Root Access

The important security property of this setup is that Jenkins should not be able to execute arbitrary commands as root.

For example, this should fail:

sudo -u jenkins sudo whoami

While this should succeed:

sudo -u jenkins sudo /var/www/cleanup.sh

You can also check the permissions available to Jenkins:

sudo -u jenkins sudo -l

The output should show that Jenkins is allowed to run only the cleanup script.

7. Why This Approach Is Safer

Avoid giving Jenkins unrestricted sudo access:

jenkins ALL=(ALL) NOPASSWD: ALL

With unrestricted access, a compromised Jenkins job could potentially execute commands such as:

sudo rm -rf /

or modify system configuration, users, SSH keys, and other sensitive resources.

Instead, use a narrowly scoped rule:

jenkins ALL=(root) NOPASSWD: /var/www/cleanup.sh

This follows the principle of least privilege: Jenkins receives only the root permission it actually needs.

8. Important Security Considerations

Keep the Script Owned by Root

Do not allow Jenkins to modify the script:

sudo chown root:root /var/www/cleanup.sh
sudo chmod 750 /var/www/cleanup.sh

If Jenkins can write to a root-executable script, it could potentially insert arbitrary root commands into that script.

Use an Absolute Script Path

Use:

sudo /var/www/cleanup.sh

rather than:

sudo cleanup.sh

The absolute path makes the sudoers rule precise and avoids ambiguity around the executable being invoked.

Avoid User-Controlled Arguments

If you want Jenkins to run:

sudo /var/www/cleanup.sh

do not unnecessarily allow:

jenkins ALL=(root) NOPASSWD: /var/www/cleanup.sh *

The latter allows Jenkins to pass arbitrary arguments to the script, which can introduce additional security concerns.

Be Careful With Commands Inside the Script

Since the script runs as root, every command inside it effectively has root privileges.

For example:

rm -rf "$SOME_DIRECTORY"

should be carefully validated if the directory path can ever be influenced by external input.

Final Configuration

The resulting setup is simple:

Jenkins
   |
   | sudo /var/www/cleanup.sh
   |
   v
sudoers
   |
   | Allows only this command
   v
/var/www/cleanup.sh
   |
   | runs as root
   v
Server cleanup operations

The key configuration is:

Script:

sudo chown root:root /var/www/cleanup.sh
sudo chmod 750 /var/www/cleanup.sh

Sudoers:

jenkins ALL=(root) NOPASSWD: /var/www/cleanup.sh

Jenkins:

sudo /var/www/cleanup.sh

This gives Jenkins the ability to perform the required root-level maintenance task while avoiding unrestricted root access.