Veröffentlicht am

API Server Hardening: Kubernetes absichern

Teilen:
Authors

API Server Hardening: So sichern Sie Ihren Kubernetes-Cluster ab

TL;DR

Der API Server ist der zentrale Einstiegspunkt in jeden Kubernetes-Cluster. Wer ihn nicht härtet, lässt die Haustür offen. Dieser Guide zeigt die wichtigsten Maßnahmen: anonyme Authentifizierung deaktivieren, Audit-Logging aktivieren, Secrets verschlüsseln, OIDC anbinden und API-Anfragen per Rate Limiting begrenzen. Alle Konfigurationen sind direkt einsetzbar.


Der kube-apiserver verarbeitet jede Interaktion mit dem Cluster -- ob kubectl-Befehle, Controller-Kommunikation oder CI/CD-Pipelines. In der Standardkonfiguration akzeptiert er anonyme Anfragen, speichert Secrets unverschlüsselt in etcd und protokolliert keine Zugriffe. Für Produktionsumgebungen ist das inakzeptabel.

# Prüfen, ob anonyme Authentifizierung aktiv ist
kubectl auth can-i --list --as=system:anonymous
# Wenn hier Berechtigungen angezeigt werden: sofort handeln

Anonyme Authentifizierung deaktivieren

Standardmäßig erlaubt Kubernetes anonyme API-Anfragen. Das bedeutet: Jeder, der den API Server erreicht, kann ohne Credentials bestimmte Endpunkte abfragen. In Managed-Kubernetes-Diensten ist dies oft bereits deaktiviert, bei Self-Managed-Clustern müssen Sie es selbst tun.

Setzen Sie das folgende Flag in der kube-apiserver-Konfiguration:

# /etc/kubernetes/manifests/kube-apiserver.yaml (Static Pod Manifest)
apiVersion: v1
kind: Pod
metadata:
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
    - name: kube-apiserver
      command:
        - kube-apiserver
        ---anonymous-auth=false
        ---authorization-mode=Node,RBAC
        ---enable-admission-plugins=NodeRestriction,PodSecurity,EventRateLimit
        ---audit-log-path=/var/log/kubernetes/audit.log
        ---audit-log-maxage=30
        ---audit-log-maxbackup=10
        ---audit-log-maxsize=100
        ---audit-policy-file=/etc/kubernetes/audit-policy.yaml
        ---encryption-provider-config=/etc/kubernetes/encryption-config.yaml
        ---tls-min-version=VersionTLS12
        ---tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Mit --anonymous-auth=false werden alle nicht authentifizierten Anfragen abgelehnt. Das Flag --authorization-mode=Node,RBAC stellt sicher, dass sowohl Node-Autorisierung als auch RBAC aktiv sind.

Audit-Logging konfigurieren

Audit-Logging beantwortet die Frage: Wer hat wann was am Cluster geändert? Ohne Audit-Logs haben Sie bei einem Sicherheitsvorfall keine Möglichkeit, den Hergang zu rekonstruieren.

# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # Secrets und RBAC-Änderungen vollständig protokollieren
  - level: RequestResponse
    resources:
      - group: ''
        resources: ['secrets']
      - group: 'rbac.authorization.k8s.io'
        resources: ['clusterroles', 'clusterrolebindings', 'roles', 'rolebindings']

  # Pod-Erstellung und -Löschung auf Request-Level
  - level: Request
    verbs: ['create', 'delete', 'patch', 'update']
    resources:
      - group: ''
        resources: ['pods']
      - group: 'apps'
        resources: ['deployments', 'daemonsets', 'statefulsets']

  # Lesezugriffe nur Metadaten
  - level: Metadata
    verbs: ['get', 'list', 'watch']

  # Health-Checks ignorieren
  - level: None
    nonResourceURLs: ['/healthz*', '/readyz*', '/livez*']

  # System-Komponenten reduzieren
  - level: None
    users: ['system:kube-scheduler', 'system:kube-proxy']
    verbs: ['get', 'list', 'watch']

Die vier Audit-Level im Überblick:

LevelWas wird protokolliertEinsatz
NoneNichtsHealth-Checks, System-Komponenten
MetadataWer, wann, was (ohne Body)Lesezugriffe
RequestMetadaten + Request-BodySchreibzugriffe
RequestResponseRequest + Response-BodySecrets, RBAC-Änderungen

Encryption at Rest für etcd

Kubernetes speichert Secrets standardmäßig Base64-kodiert in etcd -- das ist keine Verschlüsselung. Jeder mit etcd-Zugriff kann alle Secrets im Klartext lesen.

# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
      - configmaps
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-kodierter-32-byte-schlüssel>
      - identity: {}

Schlüssel generieren und Konfiguration aktivieren:

# 32-Byte-Schlüssel generieren
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)

# Bestehende Secrets neu verschlüsseln
kubectl get secrets --all-namespaces -o json | \
  kubectl replace -f -

Der identity-Provider als Fallback stellt sicher, dass bereits gespeicherte unverschlüsselte Daten weiterhin lesbar bleiben, bis sie durch erneutes Speichern verschlüsselt werden.

OIDC-Integration für zentrale Authentifizierung

Statische Token-Dateien und Client-Zertifikate skalieren nicht und lassen sich nicht widerrufen. OIDC (OpenID Connect) bindet den API Server an einen zentralen Identity Provider wie Keycloak, Azure AD oder Dex an.

# kube-apiserver OIDC-Flags
spec:
  containers:
    - name: kube-apiserver
      command:
        - kube-apiserver
        ---oidc-issuer-url=https://keycloak.unternehmen.de/realms/kubernetes
        ---oidc-client-id=kubernetes-cluster
        ---oidc-username-claim=email
        ---oidc-groups-claim=groups
        ---oidc-username-prefix=oidc:
        ---oidc-groups-prefix=oidc:

Damit können Sie RBAC-Rollen an OIDC-Gruppen binden:

# ClusterRoleBinding für OIDC-Gruppe
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: platform-engineers
subjects:
  - kind: Group
    name: oidc:platform-team
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: admin
  apiGroup: rbac.authorization.k8s.io

Verlässt ein Mitarbeiter das Team, wird der Zugriff über den Identity Provider entzogen -- ohne Cluster-Konfiguration ändern zu müssen.

API Rate Limiting mit EventRateLimit

Ohne Rate Limiting kann ein einzelner Client den API Server überlasten -- ob durch fehlerhafte Controller, CI/CD-Pipelines oder gezielte DoS-Angriffe. Der EventRateLimit Admission Controller begrenzt die Anzahl der API-Anfragen.

# /etc/kubernetes/eventratelimit-config.yaml
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
kind: Configuration
limits:
  - type: Namespace
    qps: 50
    burst: 100
    cacheSize: 2000
  - type: User
    qps: 10
    burst: 50
    cacheSize: 500
  - type: Server
    qps: 500
    burst: 1000
Limit-TypWirkungEmpfohlener Wert
ServerGlobales Limit für den gesamten API Server500-1000 QPS
NamespaceLimit pro Namespace50-100 QPS
UserLimit pro Benutzer/ServiceAccount10-50 QPS

Aktivieren Sie den Admission Controller mit dem Flag --enable-admission-plugins=EventRateLimit und verweisen Sie auf die Konfigurationsdatei mit --admission-control-config-file.

Weitere Admission Controller für Härtung

Neben EventRateLimit sollten diese Admission Controller aktiv sein:

  • NodeRestriction: Verhindert, dass Kubelets Nodes oder Pods außerhalb ihres Zuständigkeitsbereichs ändern
  • PodSecurity: Erzwingt Pod Security Standards (Baseline/Restricted) auf Namespace-Ebene
  • AlwaysPullImages: Erzwingt Image-Pull bei jedem Pod-Start, verhindert die Nutzung lokal gecachter Images durch unautorisierte Pods
# Aktive Admission Controller prüfen
kubectl -n kube-system describe pod kube-apiserver | grep enable-admission

Härtung verifizieren mit kube-bench

Nach der Konfiguration sollten Sie die Härtung gegen den CIS Kubernetes Benchmark prüfen:

# kube-bench für den API Server ausführen
docker run --rm -v /etc/kubernetes:/etc/kubernetes:ro \
  aquasec/kube-bench:latest run --targets=master

# Nur API-Server-Checks
docker run --rm -v /etc/kubernetes:/etc/kubernetes:ro \
  aquasec/kube-bench:latest run --targets=master \
  --check=1.2.1,1.2.2,1.2.3,1.2.4,1.2.5

FAQ

Funktioniert API Server Hardening auch bei Managed Kubernetes (EKS, AKS, GKE)?

Bei Managed-Kubernetes-Diensten verwaltet der Cloud-Provider den API Server. Sie können keine kube-apiserver-Flags setzen. Stattdessen nutzen Sie die provider-spezifischen Konfigurationen: EKS bietet Audit-Logging über CloudTrail, AKS über Azure Monitor, GKE über Cloud Audit Logs. OIDC-Integration ist bei allen Anbietern möglich.

Wie teste ich Änderungen am API Server, ohne den Cluster zu gefährden?

Testen Sie Konfigurationsänderungen immer zuerst in einem kubeadm-Testcluster oder mit kind/k3s. Sichern Sie vor jeder Änderung die aktuelle kube-apiserver-Manifest-Datei. Da der API Server als Static Pod läuft, startet kubelet ihn automatisch neu, wenn das Manifest geändert wird.

Verursacht Audit-Logging Performance-Probleme?

Audit-Logging erzeugt zusätzliche I/O-Last. Mit der gezeigten Policy-Konfiguration -- Health-Checks auf None, Lesezugriffe auf Metadata -- bleibt der Overhead minimal. Nutzen Sie --audit-log-maxsize und --audit-log-maxbackup, um die Dateigröße zu begrenzen. Für große Cluster empfiehlt sich ein Webhook-Backend statt File-Logging.

Was passiert, wenn der Encryption Key verloren geht?

Ohne den Encryption Key sind alle verschlüsselten Secrets unwiederbringlich verloren. Sichern Sie den Key außerhalb des Clusters, idealerweise in einem Hardware Security Module (HSM) oder einem Cloud KMS. Rotieren Sie Keys regelmäßig und testen Sie die Wiederherstellung.


Kubernetes ohne DevOps-Overhead?

Wir betreiben Ihre Kubernetes-Cluster 24/7 – Sie fokussieren auf Ihr Kerngeschäft. Ab 4.000€/Monat, DSGVO-konform, mit deutschem Support.

24/7 SupportDeutsche RechenzentrenDSGVO-konform

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