Chapter 71 -- Linux security hardening: SELinux/AppArmor, auditd, capabilities, and least privilege
In one sentence
Linux hardening is layered least privilege: reduce what a process can read, write, execute, call, bind, load, and persist, while keeping enough observability to detect when those boundaries are tested.
Why this matters
Unix permissions are necessary but not sufficient. Real services also need service accounts, limited sudo, capabilities instead of root, syscall filters, MAC policy, secret handling, patching, logging, and a way to prove the controls are working.
How it actually works
Hardening layers:
identity dedicated user/group, no shared admin account
filesystem ownership, mode bits, mount options, read-only paths
privilege sudoers scope, Linux capabilities, no_new_privs
isolation systemd sandboxing, namespaces, containers, chroot where useful
MAC SELinux or AppArmor policy
kernel seccomp, module loading rules, exploit mitigations
audit auditd/journald/SIEM events tied to real questions
Useful inspection:
id myapp 2>/dev/null || true
getcap -r /usr/bin /usr/sbin 2>/dev/null
sudo -l
aa-status 2>/dev/null || true
getenforce 2>/dev/null || true
systemctl show myapp.service -p NoNewPrivileges -p CapabilityBoundingSet 2>/dev/null
Real-world scenario
A web service runs as root only because it binds port 80. Better options:
- put a reverse proxy/load balancer in front;
- bind a high port and let the proxy listen on 80/443;
- grant only CAP_NET_BIND_SERVICE to the binary, if appropriate;
- use systemd socket activation.
The expert question is not "can I make it work?" It is "what is the smallest privilege that makes it work, and how will I notice if it tries to exceed that?"
Try it yourself
In a lab, compare a service run as your user, as root, and as a dedicated service account. List the files it can write and the ports it can bind. Then remove one privilege and observe the failure mode in logs.
Common mistakes
- Disabling SELinux/AppArmor because of one denial instead of understanding the denial and adjusting policy or application behaviour.
- Giving
NOPASSWD: ALLin sudoers for convenience. - Running containers as root and assuming "container" means "safe."
- Collecting audit logs without a detection question.
Check yourself
- Why are Linux capabilities safer than full root for narrow privileges?
- What problem do SELinux/AppArmor solve that mode bits do not?
- Why is logging a hardening control only when someone reviews or alerts on it?
Across the series
- The attacker's view of these controls: Security Engineering in Depth covers container internals and escapes (Chapter 15), Kubernetes RBAC, admission, network, and runtime security (Chapters 17–20), with a Go lab for workload identity over mTLS (Chapter 23).
- Hardening applied to one service: the systemd unit and Kubernetes manifest in Chapter 82 (exposure score 3.1 vs 9.6 unhardened).