LFCS 43 🐧 Sudo Delegation and NOPASSWD
Sudo delegation is the practice of granting specific users or groups the ability to run specific commands with elevated privileges, without giving them full root access or the root password. The NOPASSWD tag is the most consequential modifier in this delegation: it removes the password prompt entirely for the commands that follow it. For the LFCS exam, sudo delegation falls under the Users and Groups domain, where you are expected to configure sudo access and restrict privilege escalation . Understanding NOPASSWD is essential not just because it appears in exam objectives, but because misusing it is one of the fastest ways to turn a controlled privilege delegation into a permanent backdoor.
The core syntax is straightforward. A rule like deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh allows the user deploy to run that one script as root without entering a password. The tag is positional and sticky: it applies to every command listed after it on the same line until another tag overrides it . This means you can mix passwordless and password-protected commands in a single rule by using PASSWD: to restore the prompt. The security implication is severe: NOPASSWD removes the last authentication checkpoint before privileged execution. If an attacker gains a shell as a NOPASSWD-enabled user, every command covered by that tag runs as root instantly . The rule is to scope it to the narrowest, safest command set possible and never apply it to ALL.
Key point: NOPASSWD: disables the password prompt for the commands that follow it in a sudoers rule; it is positionally sticky within the rule, and because it removes the final authentication barrier, it must be scoped to specific, non-escapable commands rather than broad wildcards or ALL.
Why NOPASSWD exists and why it is dangerous
The automation problem. Many administrative tasks need to run unattended: deployment scripts, monitoring agents, backup jobs, and configuration management tools. These processes cannot type a password. NOPASSWD solves this by allowing a specific script or command to run as root without interactive authentication. The Delphix documentation, for example, uses NOPASSWD for commands like /bin/ps and /usr/bin/mount that its engine needs to run as root without a human present .
The convenience problem. Some commands are run so frequently by administrators that the password prompt becomes friction. A rule like %ops ALL=(root) NOPASSWD: /usr/bin/systemctl status * lets the operations team check service status without typing a password each time. This is a trade-off: convenience for reduced auditability. Every NOPASSWD invocation is still logged, but the authentication event that normally accompanies it is absent.
The shell escape problem. The most dangerous NOPASSWD rules are those that grant access to commands that can spawn a shell. An editor like vim can run :!/bin/sh and give you a root shell. A pager like less can run !sh. A file manager or a language interpreter can do the same. If a user has NOPASSWD access to any of these, they effectively have passwordless root access, regardless of what the rule intended . The sudoers manual is explicit: if a user has sudo ALL, there is nothing to prevent them from creating their own program that gives them a root shell, regardless of any ! elements in the rule .
The wildcard problem. A rule like NOPASSWD: /usr/bin/systemctl restart * allows the user to restart any service, including services that can be used for privilege escalation. A rule like NOPASSWD: /bin/cp * allows copying any file to any location, including overwriting /etc/sudoers or /etc/passwd. Wildcards are convenient but they broaden the attack surface. The safe pattern is to enumerate specific services or specific file paths rather than using globs.
The tag stickiness problem. NOPASSWD and PASSWD are positional. In the rule ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm, the user can run /bin/kill without a password, but /bin/ls and /usr/bin/lprm require one . If you write NOPASSWD: /bin/kill, /bin/ls, both commands are passwordless. The tag applies to everything after it until another tag appears. This is a common source of unintended passwordless access.
a. Syntax and scoping of NOPASSWD
The NOPASSWD tag appears after the run-as specification and before the command list:
WHO WHERE=(AS_WHOM) NOPASSWD: COMMAND
A complete example:
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
This grants deploy the ability to run exactly that script as root without a password. The script itself can do anything as root, so the safety of this rule depends entirely on what the script does and who can modify it. If deploy can write to /opt/deploy/run.sh, they can change the script to do anything, and the NOPASSWD rule becomes a root shell.
To mix passwordless and password-protected commands:
ops ALL=(root) NOPASSWD: /usr/bin/systemctl status nginx, PASSWD: /usr/bin/systemctl restart nginx
Here status is passwordless, restart requires a password. The PASSWD: tag restores the default behavior for the commands that follow it.
To grant NOPASSWD to a group:
%webadmins ALL=(root) NOPASSWD: /usr/bin/systemctl reload nginx
This applies to every member of webadmins. Group membership is the delegation mechanism; NOPASSWD is the authentication modifier.
The sudo -l command lists the invoking user’s privileges, including which commands are passwordless:
User deploy may run the following commands on this host:
(root) NOPASSWD: /opt/deploy/run.sh
This is the verification step: after adding a rule, run sudo -l as the target user to confirm that the NOPASSWD tag is applied as intended .
b. Delegation patterns that are safe to use with NOPASSWD
The safe pattern for NOPASSWD is a wrapper script that performs a fixed operation and takes no arbitrary arguments. A script like /opt/deploy/run.sh that reads its configuration from a root-owned file and performs a specific deployment is a reasonable candidate. The user cannot influence what the script does beyond triggering it.
# /opt/deploy/run.sh
#!/bin/bash
set -euo pipefail
cd /opt/app
git pull origin main
systemctl restart myapp
The sudoers rule:
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
The user deploy can trigger a deployment. They cannot run arbitrary commands. They cannot pass arguments that change the script’s behavior. The script is owned by root and not writable by deploy. This is a controlled delegation.
A less safe but sometimes acceptable pattern is a specific systemctl command with a fixed service:
%ops ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginx
This is scoped to one service. It does not allow restarting other services or running arbitrary systemctl commands. The risk is lower than a wildcard, but the user can still restart Nginx at will, which could be used for denial of service.
The unsafe pattern is NOPASSWD: ALL. This gives passwordless root access. It is equivalent to giving the user the root password and disabling the password prompt. There is no delegation left—it is full privilege escalation with no audit trail beyond the command logs. The same applies to wildcards like NOPASSWD: /usr/bin/* or NOPASSWD: /bin/*. These are effectively ALL with extra steps.
c. Auditing and troubleshooting NOPASSWD
The first troubleshooting step when NOPASSWD is not working is to check the rule order. Sudo uses the last matching rule it finds. If a later rule grants the same command without NOPASSWD, or with a different run-as specification, the later rule wins . This is why the order of drop-in files matters and why the main file’s rules can override drop-in rules depending on inclusion order.
The second step is to verify that the command path in the rule matches the actual path. A rule for /usr/bin/systemctl does not apply if the user runs /bin/systemctl (even if it is a symlink). Sudo matches the path as typed. If the rule specifies a full path and the user invokes the command via a different path, the rule does not match, and the default password prompt applies .
The third step is to check for requiretty. On some systems, sudo is configured with Defaults requiretty, which requires a terminal for sudo commands. If a user is running a NOPASSWD command from a non-interactive context (a cron job, a script without a TTY), the command fails even though the rule is correct. The Delphix documentation explicitly disables requiretty for this reason . The fix is to add Defaults:username !requiretty or remove the global setting.
The fourth step is to inspect the sudoers file with visudo -c to confirm syntax. A syntax error anywhere in the file can cause sudo to ignore the entire configuration or refuse to run. visudo -c -f /etc/sudoers.d/file checks a specific drop-in file.
The final step is to use sudo -l as the target user. If the rule does not appear in the output, sudo is not seeing it. That points to a file inclusion problem, a filename problem (dots or tildes), or a permissions problem (0644 instead of 0440).
Complete Example Session
The following session demonstrates a controlled NOPASSWD delegation for a deployment script, including verification and a test of the password behavior.
# ============================================
# PART 1: CREATE THE DEPLOYMENT SCRIPT
# ============================================
sudo mkdir -p /opt/deploy
sudo tee /opt/deploy/run.sh > /dev/null << 'EOF'
#!/bin/bash
set -euo pipefail
echo "Deploying application..."
systemctl restart myapp
EOF
sudo chmod 755 /opt/deploy/run.sh
sudo chown root:root /opt/deploy/run.sh
# ============================================
# PART 2: CREATE THE DEPLOY USER AND GROUP
# ============================================
sudo useradd -m -s /bin/bash deploy
sudo passwd -d deploy # no password; user will use SSH keys
# ============================================
# PART 3: CREATE THE DROP-IN RULE
# ============================================
sudo visudo -f /etc/sudoers.d/10-deploy
# Content:
# deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
# ============================================
# PART 4: VALIDATE SYNTAX
# ============================================
sudo visudo -c -f /etc/sudoers.d/10-deploy
# Output: parsed OK
# ============================================
# PART 5: VERIFY PRIVILEGES AS DEPLOY
# ============================================
sudo -l -U deploy
# Expected output includes:
# (root) NOPASSWD: /opt/deploy/run.sh
# ============================================
# PART 6: TEST THE NOPASSWD BEHAVIOR
# ============================================
su - deploy
sudo -k # clear any cached credentials
sudo /opt/deploy/run.sh
# Runs without password prompt
# ============================================
# PART 7: TEST A COMMAND NOT IN THE RULE
# ============================================
sudo /bin/ls
# Prompts for password (and fails, because deploy has no sudo access)
# ============================================
# PART 8: ADD A PASSWORD-PROTECTED COMMAND
# ============================================
sudo visudo -f /etc/sudoers.d/10-deploy
# Content:
# deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh, PASSWD: /usr/bin/systemctl status myapp
# ============================================
# PART 9: TEST MIXED TAGS
# ============================================
su - deploy
sudo -k
sudo /opt/deploy/run.sh
# No password prompt
sudo /usr/bin/systemctl status myapp
# Prompts for password (deploy has no password, so this fails
# unless deploy has another sudo rule granting it)
# ============================================
# PART 10: CLEAN UP
# ============================================
sudo rm /etc/sudoers.d/10-deploy
sudo userdel -r deploy
sudo rm -rf /opt/deploy
The ten parts cover script creation with root ownership, user creation, the NOPASSWD rule, syntax validation, privilege verification, a passwordless test, a denied command test, adding a PASSWD: scoped command, testing the mixed tags, and cleanup. What the session demonstrates is that NOPASSWD is a scoping decision: the rule grants exactly one script passwordless access, and everything else is denied or requires a password that the user may not have.
Quick Reference
NOPASSWD Syntax
| Component | Example | Meaning |
|---|---|---|
| Full rule | user ALL=(root) NOPASSWD: /path/cmd | Passwordless for one command |
| Mixed tags | NOPASSWD: /a, PASSWD: /b | /a passwordless, /b requires password |
| Group | %group ALL=(root) NOPASSWD: /path/cmd | Passwordless for group members |
Tag Behavior
| Tag | Effect |
|---|---|
NOPASSWD: | Skips password prompt for following commands |
PASSWD: | Restores password prompt for following commands |
| Default (no tag) | Password required |
Safe vs Unsafe NOPASSWD Targets
| Target | Risk | Reason |
|---|---|---|
| Fixed wrapper script (root-owned, no args) | Low | Cannot be influenced by user |
Specific systemctl restart service | Medium | Scoped, but can cause DoS |
NOPASSWD: ALL | Critical | Full passwordless root |
NOPASSWD: /bin/* | Critical | Effectively ALL |
| Editor, pager, interpreter | Critical | Shell escape |
cp, mv, rm with wildcards | High | Can overwrite system files |
Troubleshooting Commands
| Check | Command |
|---|---|
| List user privileges | sudo -l -U username |
| Clear cached credentials | sudo -k |
| Validate syntax | sudo visudo -c -f file |
| Check rule order | Inspect drop-in filenames and includedir |
Best Practices
✅ Do This:
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh # ✅ fixed script
sudo -l -U deploy # ✅ verify rule
sudo visudo -f /etc/sudoers.d/10-deploy # ✅ safe edit
chown root:root /opt/deploy/run.sh; chmod 755 # ✅ script not writable by user
❌ Don’t Do This:
deploy ALL=(root) NOPASSWD: ALL # ❌ full passwordless root
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl * # ❌ wildcard broadens scope
deploy ALL=(root) NOPASSWD: /usr/bin/vim # ❌ shell escape
deploy ALL=(root) NOPASSWD: /bin/cp * # ❌ overwrite system files
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| NOPASSWD ignored, password prompted | Rule does not match (wrong path) | Use exact absolute path |
| NOPASSWD ignored | Later rule overrides | Check rule order and last match |
| NOPASSWD fails in cron | requiretty is set | Defaults:user !requiretty |
| User has unintended passwordless access | Tag stickiness (NOPASSWD: /a, /b) | Add PASSWD: before protected commands |
| Script modified by user | Script writable by delegated user | chown root:root; chmod 755 |
| Drop-in ignored | Wrong permissions or filename | 0440, root:root, no dots |
Real-World Examples
1. Passwordless deployment script
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
2. Group passwordless service status
%ops ALL=(root) NOPASSWD: /usr/bin/systemctl status nginx
3. Mixed passwordless and password
ops ALL=(root) NOPASSWD: /usr/bin/systemctl status nginx, PASSWD: /usr/bin/systemctl restart nginx
4. Verify as target user
sudo -l -U deploy
5. Clear cached credentials
sudo -k
6. Disable requiretty for a user
Defaults:deploy !requiretty
7. Check syntax of a drop-in
sudo visudo -c -f /etc/sudoers.d/10-deploy
8. Run as another user without password
deploy ALL=(backup) NOPASSWD: /usr/bin/rsync
9. Restrict a script to no arguments
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh ""
10. Audit passwordless rules
sudo grep -r NOPASSWD /etc/sudoers /etc/sudoers.d/
Visual
NOPASSWD Tag Scope
┌──────────────────────────────────────────────┐
│ deploy ALL=(root) NOPASSWD: /opt/run.sh │
│ │ │
│ ▼ │
│ /opt/run.sh runs without password │
│ │
│ deploy ALL=(root) NOPASSWD: /bin/a, /bin/b │
│ │ │
│ ▼ │
│ Both /bin/a and /bin/b run without password │
│ (tag is sticky to the end of the line) │
│ │
│ deploy ALL=(root) NOPASSWD: /bin/a, PASSWD: /bin/b │
│ │ │
│ ▼ │
│ /bin/a passwordless, /bin/b requires password│
└──────────────────────────────────────────────┘
Safe Delegation Pattern
┌──────────────────────────────────────────────┐
│ USER (deploy) │
│ can run: /opt/deploy/run.sh │
│ │ │
│ ▼ │
│ SCRIPT (root-owned, 755, no user write) │
│ does: git pull; systemctl restart myapp │
│ │ │
│ ▼ │
│ ROOT │
│ │
│ User cannot modify the script. │
│ User cannot pass arguments. │
│ User cannot run other commands. │
└──────────────────────────────────────────────┘
Unsafe Delegation Pattern
┌──────────────────────────────────────────────┐
│ deploy ALL=(root) NOPASSWD: ALL │
│ │ │
│ ▼ │
│ User has passwordless root │
│ Can do anything │
│ No authentication checkpoint │
│ = root password shared │
└──────────────────────────────────────────────┘
Shell Escape Risk
┌──────────────────────────────────────────────┐
│ NOPASSWD: /usr/bin/vim │
│ │ │
│ ▼ │
│ User runs: sudo vim │
│ │ │
│ ▼ │
│ Inside vim: :!/bin/sh │
│ │ │
│ ▼ │
│ Root shell ❌ │
│ │
│ Same for less, more, man, python, perl, │
│ awk, find -exec, and many others │
└──────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| NOPASSWD purpose | Skip password prompt for specific commands |
| Syntax | user ALL=(root) NOPASSWD: /path/cmd |
| Tag stickiness | Applies to all following commands on the line |
| Restore password | PASSWD: tag |
| Safe target | Root-owned, fixed script with no user-writable parts |
| Unsafe targets | ALL, wildcards, editors, pagers, interpreters, cp/mv |
| Verification | sudo -l -U user |
| Clear cache | sudo -k |
| Syntax check | sudo visudo -c -f file |
Key takeaways:
NOPASSWDremoves the password prompt for the commands that follow it. It is positional and sticky within the rule; usePASSWD:to restore the prompt for specific commands .- The safe pattern is a root-owned wrapper script with no user-controlled arguments. The user triggers the script; they do not control what it does.
- Wildcards and
ALLdefeat the purpose of delegation.NOPASSWD: ALLis passwordless root.NOPASSWD: /bin/*is effectively the same. - Editors, pagers, and interpreters are shell escapes. Granting
NOPASSWDtovim,less, orpythongives root shell access regardless of the intended scope . - Rule order matters. Sudo uses the last matching rule. A later rule can override a
NOPASSWDrule and cause a password prompt . - Verify with
sudo -l. After adding a rule, check that the target user sees it and that theNOPASSWDtag appears where expected. requirettycan breakNOPASSWDin automation. If a command runs without a terminal,requirettyblocks it even when the rule is correct .
Remember: NOPASSWD is a deliberate weakening of sudo’s authentication model. It exists for automation, not for convenience. Every NOPASSWD rule should be scoped to a specific command that cannot be used to escape to a shell or modify system files. The safest rule is a fixed script owned by root and not writable by the delegated user. The most dangerous rule is NOPASSWD: ALL, which is indistinguishable from sharing the root password. For the LFCS exam, know the syntax, know the tag stickiness, and know how to verify the rule with sudo -l—but more importantly, know why the scope matters.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!