CoursesRuntime & eBPF securityKernel hardening & isolation

AppArmor & SELinux

Path-based and label-based container confinement.

Advanced35 min · lesson 5 of 15

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.

confine a container with AppArmor
# 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 these
deny 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.

Two MAC models
AppArmor (path-based)
profile per program
allowed paths, caps, network
easy to read/reason
Debian/Ubuntu default
SELinux (label-based)
type enforcement
contexts on processes + files
svirt / MCS categories
containers isolated by label
Both confine a process beyond standard permissions. Keep them enforcing — a permissive/disabled MAC is a removed layer.
setenforce 0 is a security incident waiting to happen
Flipping SELinux to permissive (or disabling AppArmor) to unblock a workload removes mandatory confinement from every container on the host. Fix the policy for the legitimate case instead; the disabled state is precisely what an attacker relies on after landing in a container.