Home / Alt manpages / sudoers(5)

  • sudoers(5)
  • File format
  • linux

Add a Least-Privilege sudoers Rule and Prove It Works

Someone needs to run one command as root, and ALL=(ALL) ALL in sudoers is not the answer. You will write one rule that lets a named user run one exact command as one target account, then check it is both valid and effective. Allow about fifteen minutes.

  • Checked against: sudo 1.9.15p5 on Ubuntu.
  • You need: an existing administrative login and a command that is safe to test.
  • Test command: /usr/bin/systemctl status ssh, because it reads service state without starting, stopping or reloading anything. Replace it only with a command whose arguments and effects you have checked.

Warning

Sudo policy is security-sensitive. A typo can grant too much access, and a syntax error can stop sudo loading its policy at all. Keep a root shell or console session open the whole time and do not close it until the new rule has been tested.

1. Record the installed sudo version

Confirm the binary and policy plugin you are about to rely on. Ordinary, read-only:

$ sudo -V | sed -n '1,5p'
Sudo version 1.9.15p5
Sudoers policy plugin version 1.9.15p5
Sudoers file grammar version 50

Package revision and plugin details may differ on another host. What matters is that you are writing for the sudoers format this version provides, not pasting a rule from an unrelated system.

Checkpoint

Your administrative session is still open, and the version is written down before you change policy.

2. Choose an exact command and target

A sudoers user specification makes four decisions:

  • Who may run the command.
  • On which host.
  • As which target user.
  • Which command, with which arguments.

Keep ALL out of it while you learn the shape: in the command position, ALL permits any command. Here the placeholder account is deploy, the host is any host, the target is root and the command is the read-only service query:

deploy ALL = (root) /usr/bin/systemctl status ssh

The path is fully qualified, and status ssh is part of the match, so a request for another unit or another systemctl subcommand does not match. Check the real path on your system:

$ command -v systemctl
/usr/bin/systemctl
$ systemctl status ssh --no-pager
host-specific service status is printed here

Warning

A command that accepts a shell, an editor, a scripting language or an option that runs another program is not a narrow capability. It can be an indirect route to a root shell even when its path looks specific.

3. Create a separate rule file

On Ubuntu, local rules belong in /etc/sudoers.d, not appended to the main file. The installed configuration reads that directory with @includedir, and there is a catch in how:

  • Skipped: files ending in ~ or containing a dot. 50-deploy.conf would be ignored.
  • Read order: the remaining files, in lexical order.
  • So: use a simple, consistently numbered name with no dot.

This needs elevated privileges. visudo locks the policy while you edit and checks the result before installing it:

$ sudo visudo -f /etc/sudoers.d/50-deploy-systemctl

Enter exactly this rule, changing only the account, target and command after checking them:

deploy ALL = (root) /usr/bin/systemctl status ssh

Save and exit. Success normally drops you back at the shell with no error. If visudo reports a syntax problem, choose the option to return to editing and fix it.

Warning

Never force installation of a file that visudo says is invalid.

Checkpoint

The file name has no dot, and the rule has a fully qualified command path.

4. Validate the complete policy

Checking only the new line is not enough: an include, alias or later rule can change the effective result. Check the whole configuration (elevated, read-only):

$ sudo visudo -c
/etc/sudoers: parsed OK
/etc/sudoers.d/50-deploy-systemctl: parsed OK

Paths and wording vary by host. You want exit status zero and parsed OK for both the main file and the included rule.

Recovery

If the check fails, keep the administrative session open and inspect the reported file. Retrying the command that needs sudo will not fix a syntax error.

5. Test as the named user

Switch to the real account or a test login. As deploy, these are ordinary commands:

deploy$ sudo -l
Matching Defaults entries for deploy on this host:
    ...

User deploy may run the following commands on this host:
    (root) /usr/bin/systemctl status ssh
deploy$ sudo -n /usr/bin/systemctl status ssh --no-pager
host-specific service status is printed here
  • sudo -l lists what the policy allows.
  • -n makes the test non-interactive: it fails rather than prompting for a password, because a prompt can hide whether the rule matched.
  • A non-zero status is not a verdict. If authentication is required and no credential is cached, the command fails; that alone does not prove the command is unauthorised.

Tip

Use the exact command and arguments from the rule. sudo systemctl status ssh.service may not match an entry for ssh, depending on the actual argument matching. Check the listing rather than guessing.

6. Understand matching, then undo

This one surprises people: when several entries match a request, sudo applies them in file order and the last match wins, not the most specific one. A broad rule in a later file can quietly override your careful restriction, which is why the full sudo -l output matters.

To remove the example, first make sure the account has another administrative route and no active session depends on the rule. Then delete the one file with elevated privileges:

$ sudo rm -- /etc/sudoers.d/50-deploy-systemctl
$ sudo visudo -c

Warning

The deletion is irreversible unless you kept a copy, and it changes access immediately for new sudo decisions.

Tip

For a temporary rollback while investigating, you can move the file to a name the include directory skips, but only after checking your deployment's policy, and then validate the complete configuration. Do not leave backup files holding live privilege rules in /etc/sudoers.d; keep them outside that directory with permissions that suit your security policy.

Done means

  • Safety net: you recorded the local sudo version and kept a recovery session open.
  • Narrow rule: it names one account, target, fully qualified command and intended arguments.
  • Right place: the rule is in a correctly named file under /etc/sudoers.d.
  • Clean parse: sudo visudo -c accepts the complete policy.
  • Effective permission: sudo -l shows the expected entry for the named user.
  • Harmless test: the exact command ran without changing service state.