Die 10 kritischsten Sicherheitsrisiken in Kubernetes-Umgebungen und wie man sie entschärfen kann.
Die OWASP Kubernetes Top 10 identifiziert die wichtigsten Sicherheitsrisiken in Kubernetes-Umgebungen. Kubernetes hat sich zum De-facto-Standard für die Container-Orchestrierung entwickelt, doch seine Flexibilität und Komplexität bringen zahlreiche Sicherheitsrisiken mit sich. Dieser Leitfaden behandelt Fehlkonfigurationen von Workloads, RBAC-Probleme, die Verwaltung von Geheimnissen, die Netzwerksegmentierung und vieles mehr.
Unsichere Workload-Konfigurationen sind das häufigste Sicherheitsproblem von Kubernetes. Container, die als Root, mit übermäßigen Privilegien, beschreibbaren Dateisystemen oder ohne Ressourcenbeschränkungen ausgeführt werden, schaffen erhebliche Angriffsflächen. Standardkonfigurationen sind oft unsicher und müssen explizit gehärtet werden.
Ein kompromittierter Container mit Root-Rechten und Host-Zugriff kann aus der Container-Sandbox entkommen, auf das Host-Dateisystem zugreifen und auf andere Workloads umschalten. Die Ausweitung von Privilegien durch einen falsch konfigurierten Pod kann zu einer vollständigen Kompromittierung des Clusters führen.
apiVersion: v1 kind: Pod metadata: name: insecure-app spec: containers: - name: app image: myapp:latest # Mutable tag! securityContext: privileged: true # Full host access! runAsUser: 0 # Running as root! volumeMounts: - mountPath: /host name: host-fs volumes: - name: host-fs hostPath: path: / # Entire host filesystem!
apiVersion: v1 kind: Pod metadata: name: secure-app spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: myapp@sha256:abc123... # Immutable digest securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1000 capabilities: drop: ["ALL"] resources: limits: cpu: "500m" memory: "256Mi" requests: cpu: "100m" memory: "128Mi"
Kubernetes RBAC (Role-Based Access Control) ist leistungsstark, aber komplex. Zu freizügige Rollen - insbesondere Cluster-Administrator-Bindungen, Wildcard-Berechtigungen und übermäßige Dienstkontenprivilegien - ermöglichen unbefugten Zugriff auf Cluster-Ressourcen, Geheimnisse und Arbeitslasten.
Ein Angreifer, der Zugriff auf ein überprivilegiertes Dienstkonto erhält, kann Geheimnisse auflisten, privilegierte Pods erstellen, Bereitstellungen ändern und zum Cluster-Administrator aufsteigen. RBAC-Wildcard-Regeln sind das Kubernetes-Äquivalent zur Gewährung von Root-Zugriff.
# ClusterRoleBinding granting cluster-admin to a service account apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: app-admin-binding subjects: - kind: ServiceAccount name: my-app # App SA with cluster-admin! namespace: default roleRef: kind: ClusterRole name: cluster-admin # Full cluster control! apiGroup: rbac.authorization.k8s.io
# Scoped Role with minimum required permissions apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-role namespace: my-app-ns rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list"] # Read-only, specific resources resourceNames: ["app-config"] # Named resource only --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-role-binding namespace: my-app-ns subjects: - kind: ServiceAccount name: my-app namespace: my-app-ns roleRef: kind: Role name: app-role apiGroup: rbac.authorization.k8s.io
Kubernetes-Secrets sind standardmäßig nur base64-kodiert und nicht verschlüsselt. Die Speicherung sensibler Daten (API-Schlüssel, Datenbankkennwörter, TLS-Zertifikate) in einfachen ConfigMaps, Umgebungsvariablen oder unverschlüsselten Secrets macht sie für jeden mit API-Zugriff sichtbar. Secrets sind auch in etcd sichtbar, wenn "encryption at rest" nicht aktiviert ist.
Offengelegte Geheimnisse ermöglichen Angreifern den Zugriff auf Datenbanken, Cloud-Konten und externe Dienste. In etcd unverschlüsselt gespeicherte Geheimnisse können von jedem mit etcd-Zugriff gelesen werden. Geheimnisse von Umgebungsvariablen sind in Pod-Spezifikationen und Prozessauflistungen sichtbar.
# Secret in plain ConfigMap — visible to anyone apiVersion: v1 kind: ConfigMap metadata: name: app-config data: DB_PASSWORD: "SuperSecret123!" # Plaintext password! API_KEY: "sk-live-abc123xyz" # API key in ConfigMap! --- apiVersion: v1 kind: Pod metadata: name: app spec: containers: - name: app image: myapp:latest envFrom: - configMapRef: name: app-config # All values as env vars!
# Use External Secrets Operator with a vault backend apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-secrets spec: refreshInterval: 1h secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: app-secrets data: - secretKey: db-password remoteRef: key: secret/myapp/db property: password --- apiVersion: v1 kind: Pod metadata: name: app spec: containers: - name: app image: myapp@sha256:abc123... volumeMounts: - name: secrets mountPath: /etc/secrets readOnly: true # Mount as read-only files volumes: - name: secrets secret: secretName: app-secrets
Ohne Richtlinien auf Clusterebene gibt es keine Leitplanken, die den Einsatz von unsicheren Workloads verhindern. Pod Security Standards (PSS), Admission Controller und Policy Engines wie OPA Gatekeeper oder Kyverno sind für die Durchsetzung von Sicherheitsgrundlagen in allen Namespaces unerlässlich.
Ohne die Durchsetzung von Richtlinien kann jeder Entwickler privilegierte Container bereitstellen, hostPath-Volumes verwenden oder Sicherheitskontrollen deaktivieren. Eine einzige falsch konfigurierte Arbeitslast kann den gesamten Cluster gefährden. Eine manuelle Überprüfung kann nicht alle Verstöße auffangen.
#!/bin/bash # No admission control — any pod spec is accepted # No Pod Security Standards configured # Anyone can deploy a privileged container kubectl run hacker-pod --image=alpine \ --overrides='{"spec":{"containers":[{ "name":"hack", "image":"alpine", "securityContext":{"privileged":true}, "command":["nsenter","--target","1","--mount","--uts","--ipc","--net","--pid","--","bash"] }]}}' # No policy blocks this — now has host root access!
# Enforce Pod Security Standards with Kyverno apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: disallow-privileged spec: validationFailureAction: Enforce background: true rules: - name: deny-privileged match: any: - resources: kinds: ["Pod"] validate: message: "Privileged containers are not allowed." pattern: spec: containers: - securityContext: privileged: "false" - name: require-run-as-non-root match: any: - resources: kinds: ["Pod"] validate: message: "Containers must run as non-root." pattern: spec: securityContext: runAsNonRoot: true
Standardmäßig können alle Pods in einem Kubernetes-Cluster ohne jegliche Einschränkungen miteinander kommunizieren. Diese flache Netzwerkarchitektur bedeutet, dass ein gefährdeter Pod jeden anderen Pod, Dienst oder sogar den Kubernetes-API-Server erreichen kann. Netzwerkrichtlinien sind für die Implementierung der Mikrosegmentierung unerlässlich.
Ohne Netzwerksegmentierung ist eine laterale Bewegung trivial. Ein kompromittierter Frontend-Pod kann direkt auf Backend-Datenbanken, interne Dienste und die Metadaten-API (169.254.169.254) zugreifen. Dies verstößt gegen das Prinzip der geringsten Privilegien auf der Netzwerkebene.
# No NetworkPolicy — all pods can communicate freely apiVersion: v1 kind: Namespace metadata: name: production # No default deny policy # No network policies at all # Any pod can reach: # - Other pods in any namespace # - Kubernetes API server # - Cloud metadata API (169.254.169.254) # - External internet
# Default deny all ingress and egress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: ["Ingress", "Egress"] --- # Allow only frontend to backend communication apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend-to-backend namespace: production spec: podSelector: matchLabels: app: backend policyTypes: ["Ingress"] ingress: - from: - podSelector: matchLabels: app: frontend ports: - port: 8080 protocol: TCP
Die Komponenten der Kubernetes-Kontrollebene (API-Server, etcd, Kubelet, Dashboard) und Anwendungsdienste können versehentlich dem Internet oder nicht vertrauenswürdigen Netzwerken ausgesetzt sein. Offengelegte Dashboards, nicht authentifizierte Kubelets und öffentlich zugängliche API-Server sind häufige Angriffsvektoren.
Offengelegte Kubernetes-Komponenten bieten direkten Zugang zur Cluster-Verwaltung. Eine unauthentifizierte Kubelet-API ermöglicht die Ausführung von Containern. Ein offenes Dashboard mit Standardanmeldeinformationen gewährt Cluster-Administrator-Zugriff. Der öffentliche etcd-Zugang macht alle Clusterdaten einschließlich der Geheimnisse zugänglich.
# Kubernetes Dashboard exposed via LoadBalancer apiVersion: v1 kind: Service metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: LoadBalancer # Public internet access! ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard # Dashboard bound to cluster-admin service account # No authentication required — full cluster access!
# Dashboard accessible only via kubectl proxy apiVersion: v1 kind: Service metadata: name: kubernetes-dashboard namespace: kubernetes-dashboard spec: type: ClusterIP # Internal only ports: - port: 443 targetPort: 8443 selector: k8s-app: kubernetes-dashboard --- # Access via: kubectl proxy, then browse to: # http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/ # Or use kubectl port-forward for secure access
Kubernetes-Cluster bestehen aus vielen Komponenten: API-Server, etcd, kubelet, kube-proxy, CoreDNS und Add-ons von Drittanbietern (Ingress-Controller, Dienstnetze, Überwachung). Falsch konfigurierte oder ungepatchte Komponenten führen zu Sicherheitslücken. Standardkonfigurationen sind oft nicht abgesichert.
Schwachstellen in Clusterkomponenten können für Remotecodeausführung, Privilegienerweiterung oder Denial-of-Service ausgenutzt werden. CVEs in Kubelet, Ingress-Controllern oder CNI-Plugins können zu Container-Eskapaden und zur Übernahme des Clusters führen. Veraltete Komponenten kumulieren bekannte Schwachstellen.
# kubelet with insecure configuration # /var/lib/kubelet/config.yaml apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration authentication: anonymous: enabled: true # Anyone can access kubelet API! webhook: enabled: false # No authorization! authorization: mode: AlwaysAllow # All requests permitted! readOnlyPort: 10255 # Unauthenticated read port open!
# Hardened kubelet configuration apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration authentication: anonymous: enabled: false # Deny anonymous access webhook: enabled: true # Use API server for auth x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook # API server authorizes requests readOnlyPort: 0 # Disable read-only port protectKernelDefaults: true eventRecordQPS: 5
Kubernetes-Cluster, die in Cloud-Umgebungen (AWS, GCP, Azure) ausgeführt werden, können auf Cloud-Metadaten-APIs und IAM-Rollen zugreifen, die den Knoten zugeordnet sind. Angreifer, die einen Pod kompromittieren, können diese nutzen, um ihre Rechte vom Cluster auf das Cloud-Konto auszuweiten und auf S3-Buckets, Datenbanken und andere Cloud-Dienste zuzugreifen.
IAM-Rollen auf Knotenebene werden an alle Pods auf diesem Knoten vererbt. Ein kompromittierter Pod kann die Metadaten-API (169.254.169.254) abfragen, um Cloud-Anmeldeinformationen zu erhalten, und dann auf jede Cloud-Ressource zugreifen, die die Knotenrolle zulässt. Dies ermöglicht laterale Bewegungen von Kubernetes in die breitere Cloud-Umgebung.
# Node IAM role with excessive permissions resource "aws_iam_role_policy_attachment" "node_admin" { role = aws_iam_role.node_role.name policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" # All pods on this node inherit admin access! } # No IMDS restrictions — any pod can get node credentials # curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
# Use IAM Roles for Service Accounts (IRSA) resource "aws_iam_role" "app_role" { name = "my-app-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Federated = aws_iam_openid_connect_provider.eks.arn } Action = "sts:AssumeRoleWithWebIdentity" Condition = { StringEquals = { "${aws_iam_openid_connect_provider.eks.url}:sub" = "system:serviceaccount:my-ns:my-app" } } }] }) } # Pod-level scoped IAM via service account annotation # Only this specific pod gets these specific permissions
Kubernetes unterstützt mehrere Authentifizierungsmechanismen: Zertifikate, Token, OIDC und Webhook-Authentifizierung. Zu den Schwachstellen bei der Authentifizierung gehören die Verwendung statischer Token, die gemeinsame Nutzung von kubeconfig-Dateien, die fehlende Rotation von Zertifikaten und die fehlende Integration mit Identitätsanbietern. Das automatische Einbinden von Dienstkonten-Tokens schafft unnötige Angriffsflächen.
Gestohlene oder durchgesickerte kubeconfig-Dateien und Token für Dienstkonten ermöglichen direkten Cluster-Zugriff. Statische Token, die nie ablaufen, bieten dauerhaften Zugriff. Ohne zentralisiertes Identitätsmanagement ist der Entzug des Zugriffs für ausgeschiedene Teammitglieder schwierig und fehleranfällig.
# Static token file for API server authentication # /etc/kubernetes/token-auth-file.csv # token,user,uid,"groups" # abc123,admin,1,"system:masters" # Static token, never expires! # Pod with auto-mounted service account token apiVersion: v1 kind: Pod metadata: name: app spec: # automountServiceAccountToken defaults to true! # Token mounted at /var/run/secrets/kubernetes.io/serviceaccount/token containers: - name: app image: myapp:latest # App doesn't need K8s API access but has a token anyway
# Disable auto-mounted token for pods that don't need API access apiVersion: v1 kind: ServiceAccount metadata: name: my-app namespace: my-app-ns automountServiceAccountToken: false # No auto-mount --- # For pods that need API access, use bound tokens with expiry apiVersion: v1 kind: Pod metadata: name: api-consumer spec: serviceAccountName: api-consumer-sa automountServiceAccountToken: false containers: - name: app image: myapp@sha256:abc123... volumeMounts: - name: token mountPath: /var/run/secrets/tokens readOnly: true volumes: - name: token projected: sources: - serviceAccountToken: expirationSeconds: 3600 # 1-hour expiry audience: api-server
Kubernetes generiert Audit-Ereignisse für API-Serveranfragen, aber die Audit-Protokollierung ist häufig deaktiviert oder falsch konfiguriert. Ohne ordnungsgemäße Protokollierung und Überwachung bleiben böswillige Aktivitäten - wie unbefugter geheimer Zugriff, RBAC-Änderungen und Containerflucht - unentdeckt. Die Überwachung der Laufzeitsicherheit auf Container- und Knotenebene ist unerlässlich.
Ohne Audit-Protokollierung arbeiten Angreifer unentdeckt. Sie können Backdoor-Dienstkonten erstellen, Geheimnisse extrahieren und Workloads verändern, ohne dass dies dokumentiert wird. Die Reaktion auf Vorfälle ist stark beeinträchtigt, wenn es keinen Prüfpfad gibt, um festzustellen, was, wann und von wem passiert ist.
# API server with no audit logging configured # kube-apiserver flags: # --audit-log-path="" # No audit log! # --audit-policy-file="" # No audit policy! # No runtime security monitoring # No alerting on suspicious activities # Container logs not collected centrally # Default log retention — logs lost on pod restart
# Comprehensive audit policy apiVersion: audit.k8s.io/v1 kind: Policy rules: # Log all secret access at Metadata level - level: Metadata resources: - group: "" resources: ["secrets"] # Log RBAC changes at RequestResponse level - level: RequestResponse resources: - group: rbac.authorization.k8s.io resources: ["clusterroles", "clusterrolebindings", "roles", "rolebindings"] # Log pod exec/attach (potential attacks) - level: Request resources: - group: "" resources: ["pods/exec", "pods/attach", "pods/portforward"] # Default: log at Metadata level - level: Metadata
| ID | Schwachstelle | Schweregrad | Schlüssel Abschwächung |
|---|---|---|---|
| K01 | Unsichere Workload-Konfigurationen | Critical | Nicht-Root, schreibgeschütztes FS, Abwurfmöglichkeiten, Ressourcenbeschränkungen |
| K02 | Übermäßig freizügige Ermächtigung | Critical | Namespace-scoped RBAC, keine Wildcards, Audit-Bindungen |
| K03 | Geheimnisse Managementfehler | Critical | Externe Geheimnisse, Verschlüsselung im Ruhezustand, File Mounts |
| K04 | Mangelnde Durchsetzung der Politik | High | Pod-Sicherheitsstandards, Kyverno/OPA Gatekeeper |
| K05 | Fehlende Netzsegmentierung | High | Standard-verweigern NetworkPolicies, Mikrosegmentierung |
| K06 | Übermäßig exponierte Komponenten | High | ClusterIP-Dienste, kubectl-Proxy, Firewall-Regeln |
| K07 | Fehlkonfigurierte Cluster-Komponenten | High | CIS Benchmark, anonyme Anmeldung deaktivieren, Patch-Management |
| K08 | Seitliche Bewegung von Cluster zu Wolke | Critical | IRSA/Workload-Identität, Block-Metadaten-API, IMDSv2 |
| K09 | Defekte Authentifizierungsmechanismen | Critical | OIDC-Integration, gebundene Token, Auto-Mount deaktivieren |
| K10 | Unzureichende Protokollierung und Überwachung | Medium | Audit-Protokollierung, Falco/Tetragon, SIEM-Integration |