What This Chapter Solves
Chapter 04 covered classic rwx, but those nine bits only express three buckets: owner, group, others. Real needs are finer — read/write for one specific person (ACLs), one specific privilege (capabilities), root for one specific command (sudoers, written correctly). This chapter adds those three layers, each with its own failure mode.
1. sudoers: A Wildcard Is A Handover Of Root
# ❌ dangerous: allows restarting *any* service — and "systemctl edit" too
deploy ALL=(root) NOPASSWD: /bin/systemctl restart *
# ✅ pinned to an exact unit, with interactive editing excluded
deploy ALL=(root) NOPASSWD: /bin/systemctl restart nginx.service
deploy ALL=(root) NOPASSWD: /bin/systemctl status nginx.servicesudo -l # what the current identity may do (with source files)
sudo -ll # long form
sudo visudo -c # syntax-check every sudoers file
sudo -u deploy sudo -l # verify the rule as the target identityNotes:
- The risk of a wildcard is not semantics but the space of argument combinations.
systemctl restart *can be steered intoeditto overwrite unit files, or into restarting whatever security boundary you built./usr/bin/vi *is even more direct —vican spawn a shell. - The safe form lists specific commands with specific arguments, and uses
Cmnd_Aliasto manage them centrally. Be careful withDefaults env_keep: keeping variables likeLD_PRELOADorPATHis the same as handing over a bypass.
2. ACLs: Permissions For One Specific Person
The nine bits cannot name a third party; ACLs can:
getfacl /srv/app/log # inspect (including default rules and the mask)
setfacl -m u:alice:rw /srv/app/log # read/write for alice alone
setfacl -m g:devs:r /srv/app/log # read-only for a group
setfacl -x u:alice /srv/app/log # remove one entry
setfacl -b /srv/app/log # clear all ACLs
setfacl -R -m u:alice:rwX /srv/app/shared # recursive (capital X: execute only on directories)setfacl -d -m u:alice:rwX /srv/app/team # -d = default: future files inherit these rules
getfacl /srv/app/team | sed -n '/^default/,$p'
# result: every new file and subdirectory under team automatically carries alice's entrymask is the confusing part of ACLs. The mask::rwx line in getfacl caps the effective permissions of all named user and named group entries:
setfacl -m u:alice:rw file
setfacl -m m::r file # mask allows r only → alice effectively gets r (shown as #effective:r--)So when “I granted rw but it does not apply”, read the mask first. Either set it explicitly (setfacl -m m::rw) or use -n so setfacl does not recompute it.
One signal worth knowing: a + at the end of the mode column in ls -l means the file carries ACLs.
ls -l /srv/app/log # -rw-rw----+ ← the + means “there is more than the nine bits show”
getfacl /srv/app/log # the whole story3. Capabilities: Splitting Root Into Pieces
Root can do everything because it carries a whole set of capabilities (cap_net_bind_service, cap_sys_admin, cap_chown, and others). Split them out and many tasks stop needing root:
getcap -r / 2>/dev/null | head # which files carry capabilities
getcap /usr/bin/ping # the classic: ping needs cap_net_raw
sudo setcap cap_net_bind_service=+ep /usr/local/bin/myapp # bind ports below 1024
getcap /usr/local/bin/myapp
sudo setcap -r /usr/local/bin/myapp # remove it| Capability | Effect | Typical use |
|---|---|---|
cap_net_bind_service | bind ports below 1024 | let a non-root process listen on 80/443 |
cap_net_raw | raw sockets | ping, packet capture |
cap_sys_admin | mounts and other heavy rights | container tooling — half of root, grant rarely |
cap_chown | change file ownership | backup and sync tools |
Notes on setcap, two traps:
- A package upgrade wipes the capability: replacing the binary loses the
setcapsetting (the xattr is not guaranteed to survive), so this action belongs in deployment automation — otherwise it silently stops working after the next update. - For services, prefer systemd’s
AmbientCapabilities=/CapabilityBoundingSet=over tagging a binary: it is more controllable, more auditable, and configuration-as-code friendly.
4. Where Each Tool Belongs (One Table)
| Tool | Granularity | Typical problem | When to use |
|---|---|---|---|
chmod/chown | owner / group / others | missing x on a directory; 644 files | daily work (chapter 04) |
| ACL | a specific user or group | “only alice may read and write this” | shared directories, collaboration |
| capabilities | a specific privilege | “non-root binding 80” | dropping service privilege, containers |
| SELinux | a specific label (context) | “the service cannot read its own directory” | mandatory access control (next chapter) |
sudoers | command-level elevation | “restarting exactly this one service” | operations delegation |
5. Hands-On Checklist
mkdir -p /tmp/acl && touch /tmp/acl/f
setfacl -m u:"$(whoami)":rw /tmp/acl/f; getfacl /tmp/acl/f | head # 1. add an ACL entry
ls -l /tmp/acl/f # 2. the trailing +
setfacl -m m::r /tmp/acl/f; getfacl /tmp/acl/f | grep -E 'mask|effective' # 3. the mask at work
setfacl -b /tmp/acl/f; ls -l /tmp/acl/f # 4. clearing it removes the +
sudo setcap cap_net_bind_service=+ep /usr/bin/env; getcap /usr/bin/env # 5. set and read back (test box)
sudo setcap -r /usr/bin/env # 6. remove immediately
sudo visudo -c # 7. sudoers syntax self-checkSummary
- A wildcard in sudoers hands over root; pin rules to exact commands and arguments, then self-check with
visudo -c. - ACLs grant permissions to specific users and groups; the mask caps named entries — when a grant “does not apply”, read the mask; a trailing
+inls -lsignals ACLs. - Default ACLs (
setfacl -d) make new files in a directory inherit permissions — the right answer for shared directories. - Capabilities split root into fine-grained powers (
cap_net_bind_service,cap_net_raw);setcapsettings are lost on package upgrades. - Four layers: chmod (three buckets) → ACL (to a person) → capabilities (to a privilege) → SELinux (to a label).
Next Up
SELinux: the enforcing/permissive/disabled modes, what a context looks like in ls -Z, the difference between chcon, restorecon and semanage fcontext, boolean switches, and the standard procedure for “the service cannot read its own directory”.
If you enjoyed this, leave a comment~