DAC vs MAC
- DAC (Discretionary Access Control) is normal file-permissions, UID/GID/rwx. The owner decides who is allowed what.
- MAC (Mandatory Access Control) is a system-wide policy that users cannot bypass. This process may write ONLY to these paths and bind ONLY these ports, regardless of what DAC says.
Both run at the same time. To allow something you need both DAC and MAC to allow it. To deny it, one of them is enough.
The implementation is Linux Security Modules (LSM): SELinux, AppArmor, SMACK, TOMOYO, Landlock. A system usually has one active.
SELinux
Common on RHEL/CentOS/Fedora/CoreOS. It works with labels:
- Each process has a context:
user:role:type:level - Each file or socket has the same kind of context
- The policy says this type may do THIS to that type
The most important part is the type (for example, httpd_t for nginx,
var_log_t for logs). There are countless rules like httpd_t may write
httpd_log_t.
Inspecting
getenforce # Enforcing / Permissive / Disabled
sestatus # full detail
ls -Z /var/log/messages # see the SELinux context of a file
ps -eZ | head # process contexts
id -Z # my context
ausearch -m AVC -ts recent # recent denials in the audit log
Modes
- Enforcing: rules apply, violations are blocked
- Permissive: rules do NOT apply, but violations are logged (for debugging and for building your own profile)
- Disabled: turned off (requires a reboot)
sudo setenforce 0 # switch to permissive on the fly
sudo setenforce 1 # back to enforcing
# Permanently in /etc/selinux/config: SELINUX=enforcing|permissive|disabled
When something breaks
The symptom: the plain chmod 755 is correct, everything checks out, but nginx still cannot read the file. Suspect SELinux:
sudo ausearch -m AVC -ts recent | tail -5
# type=AVC msg=audit(...): avc: denied { read } for pid=1234 comm="nginx"# ... scontext=system_u:system_r:httpd_t:s0
# ... tcontext=unconfined_u:object_r:user_home_t:s0
You can see it: httpd_t is trying to read user_home_t, and that is
denied. The fixes:
- Set the right label:
sudo chcon -t httpd_sys_content_t /path/file - Permanently:
sudo semanage fcontext -a -t httpd_sys_content_t '/path(/.*)?'plussudo restorecon -Rv /path - Build a custom rule (audit2allow):
sudo ausearch -m AVC -ts recent | audit2allow -M mymodule
sudo semodule -i mymodule.pp
AppArmor
Common on Ubuntu/Debian/SUSE. It works with path-based profiles rather
than labels. A profile is a file in /etc/apparmor.d/:
/usr/sbin/nginx {/etc/nginx/** r,
/var/log/nginx/* w,
/var/www/** r,
network tcp,
capability net_bind_service,
}
The binary is bound to the profile. Whatever is not allowed is denied.
Inspecting
sudo aa-status # summary: loaded profiles and their modes
cat /sys/kernel/security/apparmor/profiles
Modes
- enforce: blocks
- complain: logs but does not block (the SELinux permissive equivalent for one profile)
- disabled
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
sudo aa-disable /etc/apparmor.d/usr.sbin.nginx
Debugging
Denials land in kern.log / the journal:
sudo dmesg | grep apparmor=
sudo journalctl -k | grep DENIED
The aa-genprof <binary> utility runs the program in complain mode,
collects its accesses, and turns them into a profile. Handy for writing
your own profiles.
SELinux vs AppArmor
| SELinux | AppArmor | |
|---|---|---|
| Approach | labels on every object | path-based profiles |
| Granularity | very high | medium |
| Complexity | high | medium |
| Default | RHEL family | Ubuntu / SUSE |
| Reload | sometimes needs an FS relabel | hot-reload of profiles |
In containers (Docker, podman, k8s) both are used: the profile applies to the container process.
When people turn it off (and why that is a bad idea)
The temptation: it does not work, so turn it off. That removes a whole layer of protection. A better path:
- Switch to permissive/complain (logs without blocking)
- Work out what exactly is denied
- Adjust the policy or the label
Turning it off entirely is reasonable only when you have another isolation system in place (containers plus namespaces plus seccomp plus capabilities).
How it fits the stack
- MAC (SELinux/AppArmor): what you MAY open, listen on, or write
- DAC (file-permissions): normal rights
- capabilities: which root privileges you hold
- seccomp: which syscalls are allowed
These are four independent layers. Production servers use all four.