Skip to main content
RunBook Academy

KubernetesLXIII · Linux Security Controls in KubernetesLinux security controls

SELinux — kernel-enforced confinement on RHEL-based nodes

Advanced⏱ ~12 minkubectlsetsebool

What you'll learn

  • Explain what SELinux is and how it differs from AppArmor
  • Configure SELinux options in a Pod (`seLinuxOptions`)
  • Understand the MCS labels and how they isolate containers
  • Recognise the production failure modes (permissive mode, missing labels)

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

SELinux is the Linux Security Module on RHEL-based distributions (RHEL, CentOS, Rocky, Fedora). It is more configurable and more strict than AppArmor but also more complex to operate. Kubernetes integrates SELinux via the securityContext.seLinuxOptions field, and the default MCS label isolates containers from each other. This lesson covers SELinux, the configuration, and the production patterns.

How SELinux differs from AppArmor

AspectAppArmorSELinux
DistributionUbuntu, DebianRHEL, CentOS, Rocky
Path-basedYesNo (label-based)
ConfigurationPlain text profilesPolicies (modules)
Default labelNoneSystem default
IsolationProcess-basedMCS label per container

SELinux uses labels (user, role, type, level) instead of file paths. Every file, process, and network socket has a label; SELinux enforces access based on the labels.

The SELinux modes

SELinux has three modes:

  • Enforcing — violations are denied.
  • Permissive — violations are logged but allowed. Useful for debugging.
  • Disabled — SELinux is off. A Critical security finding.

A production cluster must run in enforcing mode. permissive is for debugging only.

# Check the mode
getenforce
# Enforcing

Multi-Category Security (MCS)

MCS is the SELinux mechanism for isolating containers from each other. Each container gets a unique MCS label (a pair of categories, e.g., s0:c1,c2). Two containers can only communicate if their MCS labels overlap.

flowchart LR
    A[Container A] -->|MCS: s0:c1,c2| B[File]
    C[Container B] -->|MCS: s0:c3,c4| D[File]
    B -.denied.-> C
    D -.denied.-> A

By default, the kubelet assigns each container a unique MCS label; the containers cannot read each other’s files. To allow communication, the labels must be set explicitly.

The seLinuxOptions field

A Pod can specify SELinux options:

apiVersion: v1
kind: Pod
metadata:
  name: api
spec:
  securityContext:
    seLinuxOptions:
      level: "s0:c1,c2"
      role: "system_r"
      type: "container_t"
      user: "system_u"
  containers:
  - name: api
    image: myapp:v1.0

The fields:

  • user — the SELinux user (typically system_u).
  • role — the SELinux role (typically system_r).
  • type — the SELinux type (typically container_t for containers).
  • level — the MCS level (a sensitivity + categories, e.g., s0:c1,c2).

A Pod without seLinuxOptions gets the kubelet’s default label, which is unique per container.

PSS restricted and SELinux

PSS restricted does not require SELinux options. It allows the kubelet’s default label. The baseline profile allows custom SELinux options.

A workload that needs to share files with another workload sets the same MCS level:

spec:
  securityContext:
    seLinuxOptions:
      level: "s0:c1,c2"

Both workloads have the same level and can read each other’s files. A workload with a different level (s0:c3,c4) cannot.

Common failure modes

  1. SELinux is in permissive mode. Violations are logged but allowed. The fix is to set the mode to enforcing.
  2. SELinux is disabled. The kernel’s LSM is off. The fix is to re-enable SELinux (requires a reboot).
  3. MCS mismatch. Two workloads that need to share files have different MCS levels. The fix is to set the same level on both.
  4. Wrong SELinux type. A workload’s type is not container_t. The fix is to set the type to container_t.

Production patterns

  1. SELinux in enforcing mode. The default for RHEL-based clusters.
  2. Default MCS per container. The kubelet’s default isolation is sufficient for most workloads.
  3. Custom MCS for shared-file workloads. Two workloads that share a volume have the same MCS level.
  4. Audit SELinux status. getenforce returns Enforcing; Disabled is a Critical finding.

Cross-course references

  • The Linux course covers SELinux in detail, including policy modules.
  • The Observability course covers the audit log entries for SELinux violations (in permissive mode).

Quiz

Knowledge check · 4 questions

  1. Q1. What does the SELinux MCS label provide?

  2. Q2. SELinux is in `enforcing` mode by default on RHEL-based distributions.

  3. Q3. Your RHEL-based cluster has SELinux in `permissive` mode. The audit log shows `SELinux: denied` for many operations. The team set `permissive` to debug a workload issue and forgot to revert. Walk the response.

    SELinux was set to `permissive` six months ago to debug a workload that needed `container_file_t` access. The workload was fixed; the mode was not reverted. The audit log shows thousands of denials.

  4. Q4. Name the four fields in `securityContext.seLinuxOptions` and explain what each one sets.

Passing score: 75%. Answers are checked in this browser.

Production discipline

SELinux is the right primitive for workload confinement on RHEL-based distributions. A defensible SELinux programme keeps the mode at enforcing, uses the kubelet’s default MCS labels for isolation, and sets custom MCS levels only when workloads must share files. A cluster whose nodes are all Enforcing has a kernel-level confinement programme that is auditable; a cluster whose nodes are Permissive or Disabled has a programme that is not.