Veröffentlicht am

Kubernetes Multi-Level Security: SELinux MLS und MCS

Teilen:
Authors

Kubernetes Multi-Level Security: MLS und Mandatory Access Control

TL;DR

  • Multi-Level Security (MLS) erzwingt Informationsflusskontrolle durch das Betriebssystem -- unabhaengig von Anwendungslogik oder Benutzerverhalten.
  • SELinux MLS implementiert das Bell-LaPadula-Modell: Lesen nach unten erlaubt (no read up), Schreiben nach oben erlaubt (no write down).
  • Multi-Category Security (MCS) ist die praxistauglichere Alternative: Pods erhalten Kategorie-Labels, die gegenseitigen Zugriff verhindern, ohne die volle MLS-Komplexitaet.
  • Namespace-basierte Sicherheitsstufen kombiniert mit Network Policies und RBAC ergeben ein mehrschichtiges Schutzkonzept.
  • Die vollstaendige MLS-Implementierung ist komplex -- fuer die meisten Umgebungen ist MCS der bessere Einstieg.

Was ist Multi-Level Security?

Multi-Level Security (MLS) ist ein Sicherheitsmodell, das verschiedene Geheimhaltungsstufen auf einem System erzwingt. Im Gegensatz zu Discretionary Access Control (DAC), bei dem der Dateneigentuemer Berechtigungen vergibt, ist MLS eine Form von Mandatory Access Control (MAC): Das Betriebssystem erzwingt die Regeln, unabhaengig davon, was Benutzer oder Anwendungen wollen.

Das zugrunde liegende formale Modell ist Bell-LaPadula:

RegelNameBedeutung
No Read UpSimple SecurityEin Subjekt darf nur Objekte auf seiner oder niedrigerer Stufe lesen
No Write DownStar PropertyEin Subjekt darf nur auf seiner oder hoeherer Stufe schreiben
TranquilityKeine AenderungDie Sicherheitsstufe eines Objekts aendert sich nicht

In der Praxis bedeutet das: Ein Pod mit der Einstufung "Intern" kann keine Daten lesen, die als "Vertraulich" klassifiziert sind. Und ein Pod mit der Einstufung "Vertraulich" kann keine Daten in einen "Intern"-Bereich schreiben.

SELinux MLS in Kubernetes

SELinux ist das gaengigste MAC-Framework unter Linux. Im MLS-Modus erweitert SELinux seine Labels um Sicherheitsstufen (Sensitivity Levels) und Kategorien.

SELinux-Label-Anatomie

Ein vollstaendiges SELinux-Label im MLS-Modus hat vier Teile:

# Format: user:role:type:sensitivity_level
# Beispiel:
# system_u:system_r:container_t:s0-s2:c0.c255

# user      = system_u
# role      = system_r
# type      = container_t
# level     = s0-s2:c0.c255
#   s0-s2   = Sensitivity Range (darf s0, s1, s2 verarbeiten)
#   c0.c255 = Category Range

MLS-Sensitivity-Stufen definieren

# SELinux MLS aktivieren (RHEL/Rocky Linux)
yum install selinux-policy-mls

# /etc/selinux/config anpassen:
# SELINUXTYPE=mls
# SELINUX=enforcing

# Filesystem relabeln und neustarten
touch /.autorelabel
reboot

# Status pruefen
sestatus
# Expected: SELinux status: enabled, Policy: mls, Mode: enforcing

Pod Security Context mit MLS-Labels

# Pod mit explizitem MLS-Label
apiVersion: v1
kind: Pod
metadata:
  name: vertraulich-service
  namespace: security-level-2
spec:
  securityContext:
    seLinuxOptions:
      user: system_u
      role: system_r
      type: container_t
      level: "s2:c100,c200"
  containers:
    - name: app
      image: registry.internal/secure-app:v1.0.0
      securityContext:
        runAsNonRoot: true
        readOnlyRootFilesystem: true
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL

Das Label s2:c100,c200 bedeutet: Dieser Pod laeuft auf Sensitivity Level 2 (Vertraulich) mit den Kategorien c100 und c200. SELinux verhindert Zugriffe auf Dateien oder Sockets mit hoeherem Level (s3) oder anderen Kategorien.

MCS: Die praxistaugliche Alternative

Multi-Category Security (MCS) ist eine vereinfachte Variante von MLS, die in den meisten Container-Runtimes bereits standardmaessig aktiv ist. Statt hierarchischer Sensitivity Levels verwendet MCS nur Kategorien zur Isolation.

Wie MCS in Kubernetes funktioniert

Wenn SELinux auf einem Node aktiv ist, weist die Container-Runtime jedem Pod automatisch ein einzigartiges MCS-Label zu:

# MCS-Label eines laufenden Pods pruefen (auf dem Node)
ps -eZ | grep container-process
# system_u:system_r:container_t:s0:c123,c456  container-process

# Zwei Pods erhalten unterschiedliche Kategorien:
# Pod A: s0:c123,c456
# Pod B: s0:c789,c012
# Pod A kann nicht auf Dateien von Pod B zugreifen

MCS-Labels explizit setzen

# Pod mit explizitem MCS-Label fuer Shared-Volume-Zugriff
apiVersion: v1
kind: Pod
metadata:
  name: producer
  namespace: shared-data
spec:
  securityContext:
    seLinuxOptions:
      level: "s0:c100,c200"
  containers:
    - name: producer
      image: registry.internal/data-producer:v2.0.0
      volumeMounts:
        - name: shared-volume
          mountPath: /data
      securityContext:
        runAsNonRoot: true
        allowPrivilegeEscalation: false
  volumes:
    - name: shared-volume
      persistentVolumeClaim:
        claimName: shared-pvc

Ein zweiter Pod mit demselben Label s0:c100,c200 kann auf dasselbe Volume zugreifen. Ein Pod mit s0:c300,c400 wuerde von SELinux blockiert.

Namespace-basierte Sicherheitsstufen

Fuer viele Organisationen ist ein Namespace-basiertes Sicherheitsmodell der pragmatische Ansatz. Jede Sicherheitsstufe erhaelt dedizierte Namespaces mit passenden Policies. Dieser Ansatz laesst sich mit Pod Security Standards pro Namespace kombinieren.

Namespace-Struktur

# Namespace fuer Sicherheitsstufe "Oeffentlich"
apiVersion: v1
kind: Namespace
metadata:
  name: sec-level-public
  labels:
    security-level: public
    pod-security.kubernetes.io/enforce: baseline
---
# Namespace fuer Sicherheitsstufe "Intern"
apiVersion: v1
kind: Namespace
metadata:
  name: sec-level-internal
  labels:
    security-level: internal
    pod-security.kubernetes.io/enforce: restricted
---
# Namespace fuer Sicherheitsstufe "Vertraulich"
apiVersion: v1
kind: Namespace
metadata:
  name: sec-level-confidential
  labels:
    security-level: confidential
    pod-security.kubernetes.io/enforce: restricted

Kyverno-Policy: Security-Level-Labels erzwingen

# Jeder Namespace muss ein Security-Level-Label haben
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-security-level
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-security-level
      match:
        any:
          - resources:
              kinds:
                - Namespace
      exclude:
        any:
          - resources:
              namespaces:
                - kube-system
                - kube-public
                - kube-node-lease
      validate:
        message: "Namespace muss ein gueltiges security-level Label haben"
        pattern:
          metadata:
            labels:
              security-level: "public | internal | confidential | restricted"

Network Policies fuer Level-Trennung

Netzwerksegmentierung ist das zentrale Werkzeug fuer Informationsflusskontrolle. Das Prinzip folgt Bell-LaPadula: Hoehere Stufen duerfen nach unten lesen, niedrigere nicht nach oben. Fortgeschrittene Patterns behandelt unser Artikel zu Network Policies.

Default-Deny und gerichtete Kommunikation

# Vertrauliche Workloads: Default-Deny
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: sec-level-confidential
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress: []
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
# Vertraulich darf interne und oeffentliche Services lesen (Read Down)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-read-down
  namespace: sec-level-confidential
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              security-level: internal
      ports:
        - protocol: TCP
          port: 443
    - to:
        - namespaceSelector:
            matchLabels:
              security-level: public
      ports:
        - protocol: TCP
          port: 443
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53

Analog dazu erhaelt der oeffentliche Namespace eine Policy, die Egress nur an andere oeffentliche Namespaces und DNS erlaubt -- damit ist "No Read Up" auf Netzwerkebene umgesetzt.

RBAC fuer Sicherheitsstufen

RBAC muss sicherstellen, dass Benutzer nur Namespaces sehen, die ihrer Freigabestufe entsprechen. Unser RBAC Enterprise Guide behandelt weitere Patterns.

# RoleBinding: Benutzer mit Freigabe "Intern"
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: internal-access
  namespace: sec-level-internal
subjects:
  - kind: Group
    name: clearance-internal
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io
---
# Hoehere Freigabe darf auch niedrigere Stufen sehen
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: confidential-reads-internal
  namespace: sec-level-internal
subjects:
  - kind: Group
    name: clearance-confidential
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: view
  apiGroup: rbac.authorization.k8s.io

Runtime Security fuer MLS-Umgebungen

MAC auf Kernel-Ebene allein reicht nicht. Runtime Security Tools wie Falco oder Tetragon erkennen Versuche, Sicherheitsstufen zu umgehen. Unser Artikel zu Runtime Security behandelt Setup und Regelwerke im Detail.

Implementierungs-Roadmap

Phase 1: Namespace-Isolation (Woche 1-4)

  • Namespaces mit Security-Level-Labels erstellen
  • Pod Security Standards pro Namespace konfigurieren
  • Default-Deny Network Policies deployen
  • RBAC-Bindings nach Freigabestufen einrichten

Phase 2: MCS-Labels (Woche 5-8)

  • SELinux auf allen Nodes aktivieren (erst Permissive, dann Enforcing)
  • MCS-Labels fuer Pods konfigurieren
  • Shared-Volume-Zugriffe mit identischen MCS-Labels testen
  • Monitoring fuer SELinux-Denials einrichten

Phase 3: Erweiterte Kontrollen (Woche 9-12)

  • Kyverno-Policies fuer Security-Level-Validierung
  • Falco-Regeln fuer Cross-Level-Erkennung
  • Level-basierte Network Policies verfeinern
  • Penetrationstest: Isolation zwischen Stufen pruefen

Wann MLS, wann MCS, wann Namespace-Isolation?

KriteriumNamespace-IsolationMCSMLS
KomplexitaetNiedrigMittelHoch
Schutz-NiveauGutSehr gutMaximal
Regulatorische PflichtNeinSeltenBehoerden, Militaer
Container-KompatibilitaetAlleFast alleEingeschraenkt
EmpfehlungStandardRegulierte BranchenNur wenn vorgeschrieben

Fuer die meisten Mittelstaendler ist die Kombination aus Namespace-Isolation, Network Policies und RBAC ausreichend. MCS bietet eine zusaetzliche Kernel-Ebene fuer regulierte Umgebungen. Vollstaendiges MLS ist nur dort sinnvoll, wo es regulatorisch gefordert wird. Grundlegende Haertungsmassnahmen finden Sie in unserem Security-Hardening-Leitfaden.

Haeufige Fehler

SELinux direkt auf Enforcing setzen. Immer mit Permissive starten und Denials analysieren. Enforcing ohne Testphase fuehrt zu nicht startenden Pods.

# Permissive Mode als Einstieg
setenforce 0
# Denials beobachten
ausearch -m avc -ts recent
# Erst nach Analyse auf Enforcing wechseln
setenforce 1

Network Policies ohne DNS-Ausnahme. Default-Deny ohne Port 53 zu kube-system blockiert alle Service-Aufloesung. Pods koennen keine Services mehr per Name ansprechen.

Fehlende Egress-Kontrolle. Nur Ingress-Policies verhindern nicht, dass ein kompromittierter Pod Daten exfiltriert. Egress-Kontrolle ist mindestens genauso wichtig wie Ingress.

Zu viele Kategorien. MCS unterstuetzt bis zu 1024 Kategorien. Starten Sie mit wenigen, klar definierten Kategorien und erweitern Sie bei Bedarf.


Sie moechten Multi-Level Security in Ihrem Kubernetes-Cluster umsetzen und benoetigen Beratung zur Architektur oder SELinux-Konfiguration? Sprechen Sie uns an fuer eine individuelle Einschaetzung.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen