Skip to content

Dieses Tool ist nicht mit The Linux Foundation, der Cloud Native Computing Foundation (CNCF) oder dem Kubernetes-Projekt verbunden und wird von diesen weder befürwortet noch gesponsert. Kubernetes und K8s sind eingetragene Marken von The Linux Foundation. EKS, GKE, AKS und andere Namen sind Marken ihrer jeweiligen Inhaber.

kubectl exec, attach und port-forward in Audit-Logs finden

Wie kubectl exec, attach, cp, port-forward und nodes/proxy in Kubernetes-Audit-Logs erscheinen, was der Befehl verrät und wie Sie Missbrauch erkennen.

Veröffentlicht am 5 Min. Lesezeit

TL;DR. kubectl exec und kubectl attach sind Requests auf die Subressourcen pods/exec und pods/attach; kubectl port-forward trifft pods/portforward. Filtern Sie auf objectRef.subresource, akzeptieren Sie sowohl create als auch get als Verb, erwarten Sie den Response-Code 101 und lesen Sie den Befehl aus den command=-Parametern in requestURI. Ein exec durch einen Service Account ist selten und sollte als hoher Schweregrad behandelt werden. Zugriff auf nodes/proxy erreicht das Kubelet direkt und ist schlimmer. Was innerhalb der Session getippt wird, wird nicht protokolliert.

Einen Befehl in einem Container auszuführen ist die ATT&CK-Technik T1609, Container Administration Command. Es ist auch das, was legitime Administratoren bei einem Ausfall am häufigsten tun. Ziel ist nicht, jedes exec zu markieren, sondern jedes exec erklärbar zu machen.

So sieht exec im Audit-Log aus

kubectl exec -it api-6c9f7d8b5-q2w8x -n shop -- sh erzeugt ein Event wie dieses (gekürzt, fiktive Namen):

{
  "verb": "create",
  "stage": "ResponseStarted",
  "requestURI": "/api/v1/namespaces/shop/pods/api-6c9f7d8b5-q2w8x/exec?command=sh&container=api&stdin=true&stdout=true&tty=true",
  "user": { "username": "alice@example.com" },
  "objectRef": { "resource": "pods", "namespace": "shop", "name": "api-6c9f7d8b5-q2w8x", "subresource": "exec" },
  "responseStatus": { "code": 101 }
}

Wissenswert:

  • Verb. Der exec-Endpunkt wird traditionell als create autorisiert und auditiert. Seit Kubernetes 1.31 streamt kubectl standardmäßig über WebSockets, und ein WebSocket-Upgrade beginnt als HTTP-GET; je nach Version sehen Sie also get. Suchen Sie nach beidem.
  • Stage. exec ist ein lang laufender Request. Das ResponseStarted-Event wird beim Öffnen der Session geschrieben, ResponseComplete erst beim Schließen. Lässt die Policy nichts weg, bekommen Sie beide.
  • Response-Code. 101 Switching Protocols heißt, die Session wurde aufgebaut. Ein 403 heißt, jemand hat es versucht und RBAC hat abgelehnt, was für sich schon interessant ist.
  • Befehl. Jedes Argument ist ein eigener, URL-kodierter command=-Parameter: command=chroot&command=%2Fhost&command=sh ergibt chroot /host sh. Da er in der URI steht, wird er auch auf Level Metadata protokolliert.

Die übrigen Felder erklärt die Anatomie eines Audit-Events.

attach, cp, debug und port-forward

Client-AktionAudit-SpurWorauf achten
kubectl attachpods/attachKein Befehl: hängt sich an den Hauptprozess des Containers
kubectl cppods/exec mit command=tarRichtung (tar cf = aus dem Pod kopieren, tar -x… = in den Pod kopieren) und Pfade
kubectl debug (Ephemeral Container)patch auf pods/ephemeralcontainers, dann pods/attachDas Image und ob es den Prozess-Namespace des Ziels teilt
kubectl port-forwardpods/portforward mit ports=Welcher Port: 5432, 6379, 3306 sind Datenbanken
kubectl proxy / API-Proxy zu einem Nodenodes/proxyDirekter Zugriff auf die Kubelet-API

kubectl cp verdient einen eigenen Blick: Eine Datei in einen Pod zu kopieren ist ein Weg, Werkzeuge abzulegen, ohne ein neues Image zu ziehen, und aus einem Pod zu kopieren ist Exfiltration über den API-Server.

kubectl port-forward öffnet einen Tunnel vom Rechner des Clients ins Pod-Netz. Er umgeht Ingress-Controller und, für den Traffic des Clients, Network Policies, die nur Pod-zu-Pod-Traffic filtern. Ein port-forward auf einen Datenbank-Pod durch eine Identität, die das sonst nie tut, ist eine starke Spur.

nodes/proxy: exec ohne exec-Event

Die Subressource nodes/proxy erlaubt es, über den API-Server mit der Kubelet-API zu sprechen. Das Kubelet kann Befehle in jedem Container dieses Nodes ausführen und dessen Logs lesen. Der API-Server auditiert den nodes/proxy-Request, aber nicht als pods/exec, sodass exec-basierte Erkennungen ihn übersehen. Die RBAC Good Practices von Kubernetes führen den Zugriff auf die Proxy-Subressource von Nodes als Weg zur Rechteausweitung.

Schlimmer noch: Wer den Kubelet-Port eines Nodes mit gültigen Zugangsdaten erreicht, spricht direkt mit ihm; diese Aufrufe erreichen nie den API-Server und erscheinen nie im Audit-Log. Hier sind die Authentifizierungs- und Autorisierungseinstellungen des Kubelets die Kontrolle.

Admin-Arbeit von Missbrauch unterscheiden

Der Analyzer auf der Startseite teilt exec in vier Regeln auf:

RegelSchweregradLogik
Interaktiver Befehl in einem Container (exec / attach)Mittelpods/exec oder pods/attach erlaubt, durch eine menschliche Nicht-System-Identität
Service Account hat Befehl in einem Container ausgeführtHochDasselbe, durch eine system:serviceaccount:-Identität
Port-Forward zu einem PodMittelpods/portforward erlaubt, Nicht-System-Identität
Kubelet-API über nodes/proxy erreichtHochnodes/proxy erlaubt, Nicht-System-Identität

Warum diese Aufteilung? Workloads führen fast nie exec in andere Pods aus. Tut ein Service Account das, ist es meist ein aus einem Pod entnommenes Token, das eine Person wiederverwendet, oft mit kubectl/ als User Agent von einer unerwarteten IP, was zwei weitere Regeln erkennen (siehe Diebstahl von Service-Account-Tokens). CI-Systeme und manche Operatoren nutzen exec legitim; setzen Sie sie nach Prüfung explizit auf die Allow-List.

Bei menschlichen Identitäten triagieren Sie jede Session mit vier Fragen:

  1. Wer und woher? Bekannter Admin, bekannter IP-Bereich, üblicher User Agent?
  2. Wann? In einem Change-Fenster oder Incident, oder zu einer ungewöhnlichen Uhrzeit?
  3. Wo? Welcher Namespace und Pod; ist es ein privilegierter Pod oder eine Komponente in kube-system?
  4. Was? Der Befehl: interaktives sh/bash oder etwas wie cat /var/run/secrets/kubernetes.io/serviceaccount/token, curl … | sh, chroot /host, nsenter?

Ein chroot /host oder nsenter --target 1 in einem Pod mit hostPath auf / oder hostPID ist ein Container-Escape; siehe privilegierte Pods und Container-Escape.

Hunting-Abfragen

Rohe JSON-Zeilen mit jq:

jq -c 'select(.objectRef.subresource == "exec" or .objectRef.subresource == "attach"
              or .objectRef.subresource == "portforward")
       | {t: .requestReceivedTimestamp, user: .user.username, ip: .sourceIPs,
          ns: .objectRef.namespace, pod: .objectRef.name,
          sub: .objectRef.subresource, uri: .requestURI, code: .responseStatus.code}' audit.log

EKS, CloudWatch Logs Insights:

fields @timestamp, user.username, sourceIPs.0, objectRef.namespace, objectRef.name, requestURI
| filter @logStream like "kube-apiserver-audit"
| filter objectRef.subresource in ["exec", "attach", "portforward"]
| sort @timestamp desc

AKS, Log Analytics (ressourcenspezifische Tabelle):

AKSAudit
| where RequestUri has "/exec" or RequestUri has "/attach" or RequestUri has "/portforward"
| project TimeGenerated, User, SourceIps, UserAgent, RequestUri, ResponseStatus

Auf GKE filtern Sie Cloud Logging auf protoPayload.methodName:"pods.exec" (sowie pods.attach, pods.portforward).

Angriffsfläche verkleinern

  • Beschränken Sie pods/exec, pods/attach und pods/portforward auf eine kleine Break-Glass-Gruppe; es sind eigene RBAC-Ressourcen, Sie können also get auf Pods ohne sie vergeben.
  • Vergeben Sie nodes/proxy weder an Personen noch an Workloads.
  • Alarmieren Sie bei jedem exec durch einen Service Account und bei jedem exec in kube-system.
  • Bewahren Sie das Audit-Log auf: exec-Sessions sind kurz, und der Pod ist morgen vielleicht weg.

FAQ

Wie erkenne ich kubectl exec in Kubernetes-Audit-Logs?

Suchen Sie Events, deren objectRef.subresource auf der Ressource pods exec (oder attach) ist. Je nach Client- und Serverversion ist das Verb create oder get, und der Response-Code ist 101, wenn das Streaming-Upgrade gelingt. Der Befehl steht in requestURI als wiederholte command=-Parameter.

Kann ich sehen, was in einer kubectl-exec-Shell getippt wurde?

Nein. Das Audit-Log zeichnet den Request auf, der die Session geöffnet hat, und dessen initialen Befehl, nicht die danach ausgetauschten Bytes. Tastatureingaben und Prozesse im Container erfordern Runtime-Werkzeuge wie Falco oder ein EDR auf dem Node.

Taucht kubectl cp in Audit-Logs auf?

Ja, als exec. kubectl cp führt über pods/exec tar im Container aus, das Audit-Event zeigt also command=tar mit seinen Argumenten in requestURI.

Verwandte Artikel

Verwandte Artikel

Krypto-Mining in Kubernetes-Clustern über Audit-Logs erkennen: Miner-Images und -Argumente, unübliche Registries, Persistenz per CronJob und DaemonSet.
Vorbereitung eines Container-Escapes in Kubernetes-Audit-Logs erkennen: privilegierte Pods, hostPID, hostNetwork, hostPath auf / und DaemonSets in kube-system.
Kubernetes-RBAC-Rechteausweitung in Audit-Logs finden: Bindings an cluster-admin, Verben escalate, bind und impersonate, Impersonation und anonymer Zugriff.

Dieses Tool ist nicht mit The Linux Foundation, der Cloud Native Computing Foundation (CNCF) oder dem Kubernetes-Projekt verbunden und wird von diesen weder befürwortet noch gesponsert. Kubernetes und K8s sind eingetragene Marken von The Linux Foundation. EKS, GKE, AKS und andere Namen sind Marken ihrer jeweiligen Inhaber.