Hardening is the art of shrinking the blast radius: if something gets compromised, what can it actually do? Three layers answer that question on Linux: sudo, PAM and mandatory access control.
sudo & sudoers: least privilege in practice
sudo rights live in /etc/sudoers (and /etc/sudoers.d/), and must be edited with visudo — it syntax-checks before saving, so a typo doesn’t lock out every admin.
# /etc/sudoers.d/carlo
carlo ALL=(ALL:ALL) ALL
%deploy ALL=(root) /usr/bin/systemctl restart nginx- grant the exact commands needed, not
ALL— the second line lets the deploy team restart nginx and nothing else NOPASSWD: ALLis a convenient way to hand over root to anyone who can run your shell: avoid it- to see what the current session may do:
sudo -l
PAM: how Linux decides who you are
Pluggable Authentication Modules are the stack of checks behind login, sudo, sshd… They live in /etc/pam.d/, one file per service, stacked top to bottom:
# /etc/pam.d/common-auth (simplified)
auth [success=1 default=ignore] pam_unix.so nullok
auth requisite pam_deny.so
auth required pam_permit.soWorth knowing:
pam_unix.so→ classic password check against/etc/shadowpam_pwquality.so→ password complexity policypam_google_authenticator.so→ cheap and effective MFA for SSH/sudo- “authentication failures” in most real-world breaches trace back to weak PAM policy — the same class of bugs you’ll meet as the OWASP Identification & Authentication Failures category
Mandatory Access Control: AppArmor vs SELinux
Even root is confined by MAC profiles that whitelist allowed operations:
| AppArmor | SELinux | |
|---|---|---|
| Model | path-based profiles | label-based policies |
| Common on | Ubuntu/Debian/SUSE | RHEL/Fedora/CentOS |
| Check status | sudo aa-status | getenforce |
| Modes | enforcing / complain | enforcing / permissive |
Containers lean on the same primitives (namespaces, cgroups, seccomp): the more you know here, the better you reason about container escape risks.
Kernel & network hardening (sysctl)
Quick wins in /etc/sysctl.d/99-security.conf, applied with sudo sysctl --system:
net.ipv4.ip_forward = 0 # this box is not a router
net.ipv4.conf.all.rp_filter = 1 # drop spoofed source addresses
net.ipv4.conf.all.accept_redirects = 0 # don't take routing advice from the network
kernel.kptr_restrict = 2 # hide kernel pointers from userspaceSSH: the front door
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no # keys only
AllowUsers carlo deploy
# then:
sudo systemctl reload sshKey-only auth plus the logging described in Logs & Auditing covers the majority of internet-facing attack surface on a small server. And remember the permission rules from Permissions & Ownership: ~/.ssh must be 700, authorized_keys must be 600, or sshd silently ignores them.