AppArmor & SELinux
Path-based and label-based container confinement.
seccomp filters syscalls; mandatory access control confines what a process can touch once a syscall is allowed. AppArmor and SELinux are the two MAC systems that stop a compromised container from reading host secrets or writing where it should not — even when it runs as root.
AppArmor: path-based confinement
AppArmor (Debian/Ubuntu) confines a program with a profile that lists the file paths, capabilities, and network operations it may use. A container profile can deny writes outside a few directories, block raw sockets, and forbid mount — so a foothold in the container cannot tamper with the host or escalate. Kubernetes applies AppArmor profiles per container, and the curated runtime/default profile is a sane baseline. Because it is path-based, AppArmor profiles are relatively easy to read and reason about.
# A minimal profile: deny writes outside /tmp and /var/run, no raw sockets.profile k8s-restricted flags=(attach_disconnected,mediate_deleted) {file,deny /** w, # default: no writes anywhere.../tmp/** rw, /var/run/** rw, # ...except thesedeny network raw, # no raw sockets (blocks some scanning/spoofing)deny mount, # no mount ops (escape hardening)}# Kubernetes (1.30+): securityContext.appArmorProfile: { type: Localhost, localhostProfile: k8s-restricted }
SELinux: label-based type enforcement
SELinux (RHEL/Fedora) confines by labels rather than paths: every process and file has a security context, and policy defines which types may interact. For containers, the svirt model assigns each container a unique MCS (Multi-Category Security) category, so even two containers running as root cannot touch each other’s files or the host’s — the labels do not match. It is more complex than AppArmor but provides very strong, default-on isolation on RHEL-based hosts. The common failure mode is setting SELinux permissive to make an error go away, which silently removes the protection.