Πώς ένα φαινομενικά «καλά στημένο» Kubernetes cluster — με μια CI/CD ταυτότητα που έχει «λίγο παραπάνω» δικαιώματα και έναν kubelet που ξεχάστηκε ανοιχτός — μετατρέπεται σε πλήρη κατάληψη του node και των μυστικών ολόκληρου του cluster, σε ένα απομονωμένο εργαστήριο που κατέχουμε εξ ολοκλήρου: recon του control surface με nmap και kube-hunter, anonymous enumeration στο API server και στον kubelet, εντοπισμός μιας RBAC misconfiguration με kubectl auth can-i, deployment ενός privileged pod που κάνει mount το host filesystem, ανάγνωση των cluster secrets και τελικά escape στον node με chroot — φτάνοντας στο flag. Κάθε βήμα εξηγείται με «τι είναι το εργαλείο», τους σημαντικούς του διακόπτες, την πραγματική εντολή και πραγματικό, αποστειρωμένο screenshot — και κλείνει με μια σκληρή ενότητα άμυνας: πώς σταματάτε κάθε ένα βήμα.
TL;DR (EN): A Kubernetes attack chain in an isolated lab: recon (nmap, kube-hunter) finds an anonymous API and open kubelet, an RBAC misconfiguration grants secret access, and a privileged hostPath pod escapes to the node — reaching cluster secrets. Covers least-privilege RBAC, PodSecurity admission and the hardening that stops each step.
Νομική σημείωση / Authorization. Όλη η δραστηριότητα εκτελέστηκε αποκλειστικά σε ένα απομονωμένο εργαστήριο που κατέχουμε εξ ολοκλήρου, σε loopback (127.0.0.1), χωρίς καμία δημοσιευμένη θύρα και χωρίς καμία γέφυρα προς LAN ή Internet. Το cluster-στόχος (audax-k8s-lab) είναι ένα σκόπιμα ευάλωτο περιβάλλον που στήσαμε εμείς. Όλα τα secrets, τα tokens και το flag είναι εργαστηριακά και ψεύτικα. Δεν στοχοποιήθηκε, δεν σαρώθηκε και δεν χρησιμοποιήθηκε κανένα πραγματικό, τρίτο ή παραγωγικό cluster. Οι τεχνικές που περιγράφονται είναι παράνομες όταν εφαρμόζονται χωρίς ρητή γραπτή εξουσιοδότηση. Χρησιμοποιήστε τις μόνο σε δικά σας ή ρητά εξουσιοδοτημένα συστήματα, στο πλαίσιο νόμιμου penetration testing και adversary validation.
Πίνακας περιεχομένων
- Εισαγωγή: γιατί το Kubernetes είναι ο νέος κρίσιμος στόχος
- Το σενάριο και το εργαστήριο
- Η αλυσίδα με μια ματιά
- Βήμα 1 — Recon: nmap και kube-hunter
- Βήμα 2 — Anonymous enumeration σε API server και kubelet
- Βήμα 3 — RBAC misconfiguration: kubectl auth can-i
- Βήμα 4 — Ο privileged / hostPath pod
- Βήμα 5 — Cluster secrets και κατάληψη του node
- Υποστηρικτικά εργαλεία: trivy και peirates
- Ολοκληρωμένη αλυσίδα
- Αντιστοίχιση σε MITRE ATT&CK for Containers
- Επαλήθευση: τι έτρεξε live και τι δηλώνεται
- Αντιμετώπιση προβλημάτων
- Άμυνα: πώς σταματάτε κάθε βήμα
- Η γωνία NIS2 / DORA για cloud-native
- Πότε δεν πρέπει να χρησιμοποιηθεί
- Σύνοψη
- Από το εργαστήριο, στο δικό σας περιβάλλον
Εισαγωγή: γιατί το Kubernetes είναι ο νέος κρίσιμος στόχος {#eisagwgi}
Το Kubernetes έχει πάψει εδώ και καιρό να είναι «τεχνολογία των startups». Είναι σήμερα η ραχοκοκαλιά της παραγωγής σε τράπεζες, ασφαλιστικές, τηλεπικοινωνίες, πλατφόρμες υγείας και δημόσιο. Ό,τι κάποτε έτρεχε σε έναν εξυπηρετητή, τώρα ζει ως δεκάδες containers που δημιουργούνται και καταστρέφονται σε δευτερόλεπτα, με ταυτότητες που δίνονται αυτόματα και δίκτυα που στήνονται δυναμικά. Αυτή η ευελιξία είναι τεράστιο πλεονέκτημα για την ανάπτυξη — και τεράστια πρόκληση για την ασφάλεια.
Το πρόβλημα δεν είναι ότι το Kubernetes είναι «ανασφαλές». Είναι ότι είναι πολύπλοκο και ασφαλές μόνο όταν ρυθμιστεί σωστά, ενώ οι προεπιλογές του και οι βιαστικές ρυθμίσεις αφήνουν συχνά ανοιχτά μονοπάτια. Στα πραγματικά engagements, η κατάληψη ενός cluster σπάνια απαιτεί κάποιο εξωτικό zero-day. Απαιτεί την αλυσιδωτή εκμετάλλευση λαθών ρύθμισης που, μεμονωμένα, μοιάζουν «διαχειρίσιμα»:
- έναν kubelet που απαντά χωρίς authentication στη θύρα
:10250, - έναν API server με ενεργό
--anonymous-auth, - μια RBAC πολιτική που έδωσε σε μια CI/CD ταυτότητα δικαιώματα να διαβάζει secrets και να δημιουργεί pods,
- και την απουσία ενός PodSecurity admission που θα εμπόδιζε τη δημιουργία ενός
privilegedpod μεhostPath.
Καθένα από αυτά, μόνο του, είναι ένα «medium» εύρημα σε μια αναφορά. Αλυσιδωμένα, οδηγούν σε node takeover — δηλαδή σε root στο ίδιο το μηχάνημα που φιλοξενεί τα containers, και από εκεί, σε όλα τα secrets, τα certificates και τα δεδομένα του cluster.
Σε αυτό το flagship άρθρο των Audax Labs στήνουμε ολόκληρη αυτή την ιστορία από άκρη σε άκρη. Τα εργαλεία που θα δούμε είναι αυτά που κάθε σοβαρός επαγγελματίας offensive security χρησιμοποιεί για την αξιολόγηση ενός cloud-native περιβάλλοντος:
- nmap — για τον εντοπισμό του control surface (ανοιχτές θύρες
6443,10250). - kube-hunter — για γρήγορη αναγνώριση γνωστών Kubernetes vulnerabilities.
- kubectl — το «σπαθί» του χειριστή:
auth can-i,get secrets,run,exec. - Το privileged / hostPath pod manifest — το εργαλείο της κλιμάκωσης.
- trivy και peirates — υποστηρικτικά, για image/config scanning και για αυτοματοποίηση των k8s attack primitives.
Η αφήγηση ακολουθεί έξι κινήσεις: recon -> anonymous enum -> RBAC hole -> privileged pod -> secrets -> node. Και όπως σε κάθε άρθρο των Audax Labs, δεν αρκούμαστε στο «τι εντολή τρέξαμε»: εξηγούμε τι κάνει το κάθε εργαλείο, ποιες είναι οι σημαντικότερες παράμετροί του, ποια εντολή δώσαμε και τι πραγματικά επέστρεψε.
Το σενάριο και το εργαστήριο {#ergastirio}
Ο στόχος μας είναι το cluster audax-k8s-lab, με έναν namespace audax-lab που φιλοξενεί μερικά «κανονικά» pods (ένα frontend, ένα backend) και ένα Secret db-credentials. Μέσα στο cluster έχουμε φυτέψει σκόπιμα τρία λάθη που, αλυσιδωτά, δίνουν πλήρη κατάληψη:
- Ο API server τρέχει με
--anonymous-auth=trueκαι μιαClusterRoleBindingπου δένει τον ενσωματωμένο ρόλοviewστον χρήστηsystem:anonymous. Δηλαδή οποιοσδήποτε χωρίς credentials μπορεί να απαριθμήσει pods. - Ο kubelet στη θύρα
:10250τρέχει μεauthorization-mode=AlwaysAllow— δηλαδή απαντά σε αιτήματα χωρίς authentication, εκθέτοντας τη λίστα των pods και το endpoint εκτέλεσης εντολών. - Ένας ServiceAccount
ci-runner(μια ταυτότητα CI/CD pipeline) έχει ένανRoleπου του δίνειget/list/watchπάνω σε secrets καιcreateπάνω σε pods καιpods/exec. Αυτός ο συνδυασμός — «διάβασε secrets» + «φτιάξε pods» — είναι, όπως θα δούμε, θανατηφόρος.
Τοπολογία

Η μηχανή επίθεσης έχει απόλυτα ουδέτερη ταυτότητα χειριστή (kali@lab) και διαθέτει το σύνηθες cloud-native offensive stack: nmap 7.94, kube-hunter, kubectl, trivy, peirates, και τα δικά μας εργαστηριακά scripts.
Σημαντική διαφάνεια (θα την επαναλάβουμε στην ενότητα Επαλήθευση): ο σκληρά ρυθμισμένος host πάνω στον οποίο τρέξαμε δεν είχε ενεργό docker daemon ούτε δικαιώματα root, οπότε δεν σηκώσαμε live cluster (kind/minikube/k3s). Αντ’ αυτού στήσαμε έναν πραγματικό loopback kube-apiserver/kubelet stand-in που ακούει στις κανονικές θύρες 6443 και 10250 του Kubernetes και σερβίρει αποκρίσεις παραγόμενες από τα αληθινά manifests που ελέγχουμε. Έτσι, το nmap, το curl (anonymous και authenticated) και η λογική του kubectl auth can-i έτρεξαν πραγματικά. Τα βήματα που απαιτούν ζωντανό kubelet (το kubectl apply/exec στον privileged pod, το chroot /host) παρουσιάζονται με σαφή αποκάλυψη ως ανακατασκευές — αλλά τα ίδια τα manifests, η RBAC και το μοντέλο του cluster είναι αληθινά και schema-valid.
Η αλυσίδα με μια ματιά {#alysida}

Η διαδρομή είναι γραμμική και «διδακτική»: κάθε βήμα ξεκλειδώνει το επόμενο. Ξεκινάμε χωρίς κανένα credential — μόνο με δικτυακή ορατότητα προς το control surface. Καταλήγουμε με root στον node και το flag στα χέρια μας. Ας τη διατρέξουμε βήμα προς βήμα.
Βήμα 1 — Recon: nmap και kube-hunter {#recon}
Τι είναι το nmap και ο ρόλος του εδώ
Το nmap είναι ο de facto network scanner. Στο πλαίσιο του Kubernetes, ο ρόλος του είναι απλός αλλά κρίσιμος: να μας πει ποιες θύρες του control plane είναι προσβάσιμες. Ένα υγιές, καλά κλειδωμένο cluster δεν εκθέτει τον API server (6443) και σίγουρα ποτέ τον kubelet (10250) σε μη έμπιστα δίκτυα. Αν τα βλέπουμε ανοιχτά, έχουμε ήδη την πρώτη ένδειξη προβλήματος.
| Παράμετρος | Τι κάνει | Γιατί εδώ |
|---|---|---|
-sT | TCP connect scan | Αξιόπιστο χωρίς root privileges |
-Pn | Παράλειψη host discovery | Ο host απαντά ούτως ή άλλως |
-p 6443,10250,10255,2379,2380 | Στόχευση των k8s θυρών | apiserver, kubelet, read-only kubelet, etcd |
-sV | Service/version detection | Επιβεβαίωση τι «μιλάει» στη θύρα |
Hardening για Kubernetes RBAC, containers και cloud metadata (SSRF/IMDS). Αφήστε εταιρικό email και σας το στέλνουμε.
Πραγματική εντολή και έξοδος
nmap -sT -Pn -p 6443,10250,10255,2379,2380 127.0.0.1

Το αποτέλεσμα είναι σαφές: οι θύρες 6443 (kube-apiserver) και 10250 (kubelet) είναι open. Η etcd (2379/2380) και ο read-only kubelet (10255) είναι κλειστές — καλό, αλλά δεν μας σταματά. Δύο ανοιχτές θύρες control plane αρκούν για να ξεκινήσουμε.
kube-hunter: γρήγορη αναγνώριση γνωστών αδυναμιών
Το kube-hunter (της Aqua Security) είναι ένα εργαλείο ειδικά για Kubernetes: «κυνηγάει» γνωστές αδυναμίες σε ένα cluster, από open kubelet και anonymous API access μέχρι δυνατότητα RCE. Τρέχει σε λειτουργία --remote (σαρώνει έναν host από έξω) ή --pod (μέσα από ένα pod, για να δει τι βλέπει ένας παραβιασμένος workload).
| Παράμετρος | Τι κάνει |
|---|---|
--remote <ip> | Σάρωση απομακρυσμένου host |
--pod | Σάρωση «από μέσα» (attacker’s pod perspective) |
--report plain/json | Μορφή αναφοράς |
--active | Ενεργές δοκιμές (πιο επιθετικό — μόνο με άδεια) |
kube-hunter --remote 127.0.0.1 --report plain

Το kube-hunter επιβεβαιώνει και «ονοματίζει» αυτά που είδαμε: KHV005 (πρόσβαση στον API server), KHV002 (readable kubelet API), και το σοβαρότερο, KHV036 (anonymous kubelet exec). Αυτό το screenshot είναι δηλωμένη ανακατασκευή (το kube-hunter δεν ήταν εγκατεστημένο στον host), αλλά κάθε εύρημά του αντιστοιχεί σε πραγματικά ανοιχτή υπηρεσία που επιβεβαιώνεται από το nmap και το curl παρακάτω.
Βήμα 2 — Anonymous enumeration σε API server και kubelet {#anon}
Ο API server χωρίς credentials
Ο kube-apiserver είναι η καρδιά του cluster: κάθε αλληλεπίδραση περνά από αυτόν. Όταν τρέχει με --anonymous-auth=true (που ιστορικά ήταν και προεπιλογή σε αρκετές διανομές), δέχεται αιτήματα ως χρήστη system:anonymous. Αν αυτός ο χρήστης έχει οποιονδήποτε ρόλο δεμένο πάνω του — όπως το view στο lab μας — τότε οποιοσδήποτε στο δίκτυο μπορεί να απαριθμήσει πόρους.
Με απλό curl (χωρίς κανένα token) ρωτάμε πρώτα την έκδοση και μετά τα pods και τα secrets:
curl -sk https://127.0.0.1:6443/version
curl -sk https://127.0.0.1:6443/api/v1/namespaces/audax-lab/pods # anonymous
curl -sk https://127.0.0.1:6443/api/v1/namespaces/audax-lab/secrets # anonymous

Το αποτέλεσμα είναι διδακτικό: ο anonymous χρήστης μπορεί να δει τη λίστα των pods (200 OK, μας δίνει web-frontend-6c9 και api-backend-5f2) — αλλά δεν μπορεί να διαβάσει secrets (403 Forbidden). Ο λόγος είναι σημαντικός και πραγματικός: ο ενσωματωμένος ρόλος view του Kubernetes εξαιρεί ρητά τα secrets. Άρα το anonymous access μας δίνει πληροφορία (ονόματα pods, δομή του namespace) αλλά όχι ακόμα τα «κοσμήματα». Χρειαζόμαστε μια ταυτότητα με περισσότερα δικαιώματα.
Ο kubelet: το πιο υποτιμημένο σημείο εισόδου
Ο kubelet είναι ο agent που τρέχει σε κάθε node και διαχειρίζεται τα containers του. Το API του στη θύρα :10250 είναι εξαιρετικά ισχυρό — μπορεί να δώσει λίστα pods, logs, ακόμα και εκτέλεση εντολών μέσα σε container. Όταν τρέχει με authorization-mode=AlwaysAllow, απαντά χωρίς καμία πιστοποίηση:
curl -sk https://127.0.0.1:10250/pods | jq .

Ο kubelet μας επιστρέφει τη λίστα όλων των pods στον node — συμπεριλαμβανομένων και αυτών του kube-system. Το /pods είναι μόνο η αρχή· το POST /run/<ns>/<pod>/<container> επιτρέπει anonymous command execution μέσα σε οποιοδήποτε container. Ένας εκτεθειμένος kubelet είναι, από μόνος του, συχνά αρκετός για πλήρη κατάληψη. Στο σενάριό μας τον κρατάμε ως «δεύτερο δρόμο» και συνεχίζουμε μέσω της RBAC misconfiguration, που είναι και το πιο διδακτικό εύρημα.
Βήμα 3 — RBAC misconfiguration: kubectl auth can-i {#rbac}
Τι είναι το RBAC και γιατί «σπάει»
Το RBAC (Role-Based Access Control) του Kubernetes καθορίζει «ποιος μπορεί να κάνει τι, πού». Δουλεύει με Roles (σύνολα δικαιωμάτων) και RoleBindings (που δένουν έναν ρόλο σε έναν χρήστη ή ServiceAccount). Η φιλοσοφία του είναι additive και deny-by-default: ό,τι δεν επιτρέπεται ρητά, απαγορεύεται.
Το πρόβλημα δεν είναι το μοντέλο· είναι η χρήση του. Στην πράξη, ομάδες DevOps δίνουν συχνά «γενναιόδωρα» δικαιώματα σε CI/CD pipelines για να «δουλέψουν τα deployments», και αυτά τα δικαιώματα μένουν εκεί για πάντα. Ένας pipeline runner σχεδόν ποτέ δεν χρειάζεται να διαβάζει όλα τα secrets ενός namespace ή να δημιουργεί αυθαίρετα pods — κι όμως, αυτό είναι από τα πιο συχνά ευρήματα σε πραγματικά k8s assessments.
kubectl auth can-i: η «πυξίδα» του επιτιθέμενου
Το kubectl είναι το επίσημο CLI του Kubernetes. Μία από τις πιο χρήσιμες υποεντολές του — τόσο για admins όσο και για attackers — είναι το auth can-i: ρωτάει τον API server «μπορώ να κάνω αυτή την ενέργεια;» χωρίς να την εκτελεί.
| Παράμετρος / Χρήση | Τι κάνει |
|---|---|
auth can-i <verb> <resource> | Ρωτά αν επιτρέπεται μια ενέργεια |
auth can-i --list | Πλήρης λίστα δικαιωμάτων του subject |
--as=<user> / --as=system:serviceaccount:<ns>:<sa> | Impersonation ελέγχου |
-n <namespace> | Στόχευση namespace |
get secrets -o yaml | Ανάγνωση secret (η «απόληξη») |
Ρωτάμε τι μπορεί να κάνει ο ServiceAccount ci-runner:
kubectl auth can-i --list \
--as=system:serviceaccount:audax-lab:ci-runner -n audax-lab

Και εδώ αποκαλύπτεται η αλυσίδα: ο ci-runner μπορεί να κάνει get/list σε secrets και create σε pods και create σε pods/exec. Ο συνδυασμός αυτός είναι το κλειδί. Το «διάβασε secrets» μας δίνει άμεσα τα credentials του namespace. Το «φτιάξε pods» μας δίνει τον δρόμο για κλιμάκωση στον ίδιο τον node.
Πώς παράχθηκαν αυτές οι απαντήσεις: το yes/no δεν είναι «ζωγραφισμένο». Υπολογίστηκε από ένα δικό μας script (rbac_eval.py) που φορτώνει τα πραγματικά Role/RoleBinding/ClusterRoleBinding YAML του lab και εφαρμόζει την ίδια additive-allow, deny-by-default λογική με τον RBAC authorizer του API server. Γι’ αυτό, σωστά, ο anonymous χρήστης βγαίνει no στα secrets (το view τα εξαιρεί) ενώ ο ci-runner βγαίνει yes.
Βήμα 4 — Ο privileged / hostPath pod {#privpod}
Από «δημιουργώ pods» σε «είμαι root στον node»
Εδώ γίνεται το πιο σημαντικό εννοιολογικό άλμα. Το δικαίωμα «δημιουργώ pods» ακούγεται αθώο — «τι κακό μπορεί να κάνει ένα ακόμη container;». Η απάντηση: τα πάντα, αν το container ζητηθεί με τα σωστά (δηλαδή τα λάθος) χαρακτηριστικά ασφαλείας. Ένας attacker που μπορεί να δημιουργήσει pods μπορεί να ζητήσει έναν pod που:
- τρέχει
privileged: true— έχει όλα τα Linux capabilities, χωρίς seccomp/AppArmor περιορισμούς· - έχει
hostPID: true— βλέπει όλες τις διεργασίες του node· - κάνει mount το
hostPath: /— έχει ολόκληρο το root filesystem του node, με δικαίωμα εγγραφής.
Μέσα από έναν τέτοιο pod, ένα απλό chroot /host είναι, ουσιαστικά, root shell στον ίδιο τον node. Και ο node φιλοξενεί όλα τα άλλα pods — άρα και τα δικά τους secrets, τα kubelet certificates, τα δεδομένα.
Το πραγματικό manifest
| Πεδίο | Τιμή | Κίνδυνος |
|---|---|---|
securityContext.privileged | true | Όλα τα capabilities, container escape |
hostPID | true | Ορατότητα διεργασιών του node |
volumes.hostPath.path | / | Πλήρες root FS του node |
serviceAccountName | ci-runner | Κληρονομεί και το token του SA |
cat pod-privesc.yaml
kubectl apply -f pod-privesc.yaml # επιτρέπεται από την RBAC του ci-runner

Το manifest που βλέπετε είναι πραγματικό και schema-valid — το επαληθεύσαμε με parsing. Το kubectl apply/exec απαιτεί ζωντανό kubelet, οπότε αυτό το κομμάτι είναι δηλωμένη ανακατασκευή· αλλά ο μηχανισμός είναι απολύτως αληθινός και είναι από τους πιο κοινούς δρόμους container escape στην πραγματικότητα. Σημειώστε ότι ο pod ζητείται με serviceAccountName: ci-runner, οπότε κληρονομεί και το API token του SA — μια δεύτερη «λαβή» για τον attacker.
Βήμα 5 — Cluster secrets και κατάληψη του node {#secrets}
Έχουμε πλέον δύο ανεξάρτητους δρόμους προς το ίδιο αποτέλεσμα. Ο πρώτος: με το δικαίωμα get secrets του ci-runner, διαβάζουμε απευθείας το db-credentials:
curl -sk -H 'Authorization: Bearer <ci-token>' \
https://127.0.0.1:6443/api/v1/namespaces/audax-lab/secrets
echo ZmxhZ3th...fQ== | base64 -d

Τα secrets του Kubernetes είναι απλώς base64-encoded, όχι encrypted από προεπιλογή (εκτός αν έχει ρυθμιστεί encryption-at-rest). Έτσι, ένα base64 -d μας δίνει καθαρά το DB_PASSWORD και το flag:
flag{audax_lab_k8s_rbac_privpod_hostpath_node_pwned}
Ο δεύτερος δρόμος — μέσω του privileged pod — είναι ακόμα πιο καταστροφικός: chroot /host μας δίνει uid=0(root) στον node. Από εκεί, το /host/var/lib/kubelet/pki περιέχει το client certificate του kubelet, που μπορεί να αναβαθμιστεί σε δικαιώματα ολόκληρου του cluster· και όλα τα secrets κάθε namespace, μαζί με τα δεδομένα του etcd (αν ο node το φιλοξενεί), γίνονται προσβάσιμα. Αυτό είναι το T1611 — Escape to Host της MITRE, και είναι το σημείο όπου ένα «medium» εύρημα RBAC γίνεται «critical» κατάληψη υποδομής.
CHAIN COMPLETE: recon -> anonymous enum -> RBAC hole -> privileged pod -> secrets -> node + flag.
Υποστηρικτικά εργαλεία: trivy και peirates {#support}
trivy: image και configuration scanning
Το trivy (Aqua Security) είναι από τα πιο δημοφιλή εργαλεία της κοινότητας για scanning: βρίσκει CVEs σε container images, misconfigurations σε IaC/Kubernetes manifests, εκτεθειμένα secrets και άλλα. Στο πλαίσιο του δικού μας chain, το trivy config πάνω στα ίδια μας τα manifests «πιάνει» ακριβώς τα λάθη που εκμεταλλευτήκαμε — δηλαδή είναι το εργαλείο που θα τα είχε προλάβει.
| Εντολή | Τι κάνει |
|---|---|
trivy config <dir> | Σάρωση IaC/k8s manifests για misconfig |
trivy image <image> | CVEs σε container image |
trivy k8s cluster | Σάρωση ζωντανού cluster |
--severity HIGH,CRITICAL | Φιλτράρισμα σοβαρότητας |
trivy config lab/manifests/

Το trivy επισημαίνει το privileged, το hostPath, το hostPID και τη γενναιόδωρη RBAC — καθένα με το δικό του AVD/KSV αναγνωριστικό. Αυτό το screenshot είναι δηλωμένη ανακατασκευή (το trivy δεν ήταν δυνατό να εγκατασταθεί offline στον συγκεκριμένο host), αλλά κάθε εύρημα αντιστοιχεί σε πραγματικό κανόνα στα manifests που ελέγχουμε. Το μήνυμα για τους αμυνόμενους: ένα απλό trivy config στο CI/CD θα είχε μπλοκάρει το 02-privileged-pod.yaml πριν καν φτάσει στο cluster.
peirates: αυτοματοποίηση των k8s attack primitives
Το peirates (InGuardians) είναι ένα offensive framework ειδικά για Kubernetes: όταν ένας attacker αποκτήσει shell σε ένα pod, το peirates αυτοματοποιεί τα επόμενα βήματα — εντοπισμό του SA token, απαρίθμηση secrets, deployment attacker pods με hostPath, kubelet exec, ακόμα και άντληση cloud IAM credentials.
./peirates

Το peirates «συσκευάζει» ακριβώς την αλυσίδα που εκτελέσαμε χειροκίνητα: επιλογή 5 για τα secrets, επιλογή 20 για τον privileged pod με hostPath /. Και αυτό είναι δηλωμένη ανακατασκευή (χρειάζεται ζωντανό cluster), αλλά δείχνει καθαρά πόσο εύκολο και γρήγορο γίνεται το post-exploitation όταν οι primitives υπάρχουν. Ένας attacker δεν χρειάζεται να είναι Kubernetes expert· χρειάζεται μόνο ένα εκτεθειμένο token.
Ολοκληρωμένη αλυσίδα {#walkthrough}
Ας συνδέσουμε τα πάντα σε μία αφήγηση «από το exposed API στα secrets»:
- Recon. Το
nmapδείχνει6443και10250open. Τοkube-hunterβαφτίζει τα ευρήματα: anonymous API access, readable kubelet, anonymous exec. - Anonymous enum. Χωρίς κανένα credential, το
curlστον API server μας δίνει τη λίστα των pods (200) αλλά όχι τα secrets (403— τοviewεξαιρεί secrets). Ο kubelet στο:10250μας δίνει όλα τα pods του node χωρίς authentication. - RBAC hole. Το
kubectl auth can-i --listγια τονci-runnerαποκαλύπτει τον θανατηφόρο συνδυασμό: read secrets + create pods + exec. - Privileged pod. Με το δικαίωμα δημιουργίας pods, κάνουμε
applyένα manifest μεprivileged: true,hostPID: trueκαιhostPath: /. - Secrets & node. Διαβάζουμε το
db-credentials(base64, όχι encryption) και, μέσω του pod, κάνουμεchroot /host-> root στον node. Το flag είναι δικό μας.
Το κρίσιμο δίδαγμα: κανένα από αυτά τα βήματα δεν ήταν exploit. Ήταν όλα «legitimate» ενέργειες που το cluster επέτρεπε. Αυτό ακριβώς κάνει τα cloud-native misconfigurations τόσο επικίνδυνα — και τόσο δύσκολα να τα «δει» ένα κλασικό vulnerability scanner.
Αντιστοίχιση σε MITRE ATT&CK for Containers {#mitre}
Για να μιλήσουμε τη «γλώσσα» των αμυνόμενων ομάδων, αντιστοιχίζουμε κάθε βήμα στο MITRE ATT&CK for Containers, το εξειδικευμένο matrix για containerized περιβάλλοντα.

| Τακτική | Technique | Στο chain μας |
|---|---|---|
| Reconnaissance | T1046 Network Service Discovery | nmap — εντοπισμός 6443/10250 |
| Discovery | T1613 Container & Resource Discovery | kube-hunter / anonymous API+kubelet enum |
| Credential Access | T1552.007 Container API | Unauthenticated πρόσβαση σε kubelet & API server |
| Discovery | T1069 Permission Groups Discovery | kubectl auth can-i (RBAC enumeration) |
| Execution / PrivEsc | T1610 Deploy Container | Privileged hostPath pod μέσω της RBAC του ci-runner |
| Credential Access | T1552.001 Credentials in Files | Ανάγνωση του db-credentials Secret |
| Privilege Escalation | T1611 Escape to Host | chroot /host μέσω hostPath:/ + privileged -> node |
Η αντιστοίχιση αυτή δεν είναι ακαδημαϊκή άσκηση: επιτρέπει στην ομάδα άμυνας να χαρτογραφήσει ποια detection έχει (ή δεν έχει) για κάθε τεχνική — π.χ. αν το audit logging του API server θα «έπιανε» το T1610, ή αν υπάρχει runtime sensor (Falco/eBPF) που θα εντόπιζε το T1611.
Επαλήθευση: τι έτρεξε live και τι δηλώνεται {#epalithefsi}
Στα Audax Labs, η διαφάνεια για το «τι είναι πραγματικό» είναι μέρος της ποιότητας. Να ακριβώς τι στάτους έχει κάθε κομμάτι:
Έτρεξε πραγματικά (real, verifiable):
- Το
nmapέτρεξε live ενάντια στον loopback stand-in· οι θύρες6443και10250επιστράφηκαν πραγματικά ως open. - Το
curlανέκτησε πραγματικά τις αποκρίσεις: anonymous200στα pods, anonymous403στα secrets, authenticated200με το token τουci-runner, και το/podsτου kubelet. - Το
kubectl auth can-iαναπαράγεται από τοrbac_eval.py, που υπολογίζει τα yes/no από τα αληθινάRole/RoleBindingYAML με τη σωστή RBAC λογική. - Το flag αποκωδικοποιήθηκε πραγματικά με
base64 -dκαι είναι τοflag{audax_lab_k8s_rbac_privpod_hostpath_node_pwned}. - Τα manifests (RBAC, privileged pod, secret) είναι πραγματικά αρχεία, schema-valid (επαληθεύτηκε με YAML parsing).
Δηλώνεται (disclosed reconstruction):
- Ο host δεν είχε ενεργό docker daemon ούτε root, άρα δεν σηκώθηκε live cluster (kind/minikube/k3s). Χρησιμοποιήσαμε loopback kube-apiserver/kubelet stand-in που σερβίρει δεδομένα από τα αληθινά manifests.
- Τα screenshots
02-kube-hunter,08-trivy,09-peiratesείναι ανακατασκευές (τα εργαλεία δεν ήταν εγκατεστημένα/εγκαταστάσιμα offline). Κάθε τιμή σε αυτά συμφωνεί με το πραγματικό μοντέλο του lab. - Το
kubectl applyτου privileged pod και τοchroot /hostαπαιτούν ζωντανό kubelet και παρουσιάζονται ως δηλωμένη ανακατασκευή· ο μηχανισμός, όμως, είναι απολύτως πραγματικός.
Αυτή η ειλικρίνεια δεν αδυνατίζει το άρθρο — το κάνει αξιόπιστο. Το τεχνικό δίδαγμα (η αλυσίδα RBAC -> privileged pod -> node) στέκει ακριβώς επειδή στηρίζεται σε αληθινά objects και αληθινή RBAC λογική.
Αντιμετώπιση προβλημάτων {#troubleshooting}
Μερικά πρακτικά σημεία που συναντά κανείς όταν στήνει ένα τέτοιο lab:
- Ο kubelet δεν απαντά στο
:10250. Σε σύγχρονες διανομές, ο kubelet τρέχει μεauthorization-mode=Webhookκαι--anonymous-auth=falseαπό προεπιλογή. Για το lab, τοAlwaysAllowείναι σκόπιμη ρύθμιση· σε παραγωγή, μην το αγγίξετε ποτέ. - Το
kubectl auth can-iβγάζειnoπαντού. Ελέγξτε ότι τοRoleBindingδείχνει στο σωστό namespace και ότι τοsubjectsέχει το σωστόsystem:serviceaccount:<ns>:<name>. Ένα λάθος στο namespace είναι το πιο συχνό. - Ο anonymous χρήστης βλέπει secrets — δεν θα έπρεπε! Αν ναι, κάποιος έδεσε ρόλο ισχυρότερο του
view(π.χ.edit/adminή custom role με secrets) στοsystem:anonymousή στοsystem:unauthenticated. Αυτό είναι critical εύρημα. - Το
hostPath: /απορρίπτεται. Καλό σημάδι: σημαίνει ότι υπάρχει PodSecurity admission (restricted/baseline) ή κάποιο policy engine (OPA/Kyverno) που μπλοκάρει. Ακριβώς αυτό θέλουμε στην παραγωγή. - Τα secrets είναι base64, όχι κρυπτογραφημένα. Αυτό δεν είναι bug· είναι η προεπιλογή. Ενεργοποιήστε encryption-at-rest για να μην είναι απλή η ανάγνωσή τους από όποιον έχει API πρόσβαση.
Πόσο εκτεθειμένο είναι το Kubernetes cluster σας;
Anonymous API access, χαλαρό RBAC και privileged pods οδηγούν σε πλήρη κατάληψη cluster και node. Η Audax ελέγχει την cloud-native υποδομή σας με στοχευμένο offensive assessment.
Ζητήστε offensive assessment →Άμυνα: πώς σταματάτε κάθε βήμα {#amyna}
Εδώ είναι η ουσία για κάθε ομάδα που τρέχει Kubernetes. Η καλή είδηση: κάθε βήμα της αλυσίδας έχει έναν συγκεκριμένο, πρακτικό τρόπο να σταματήσει.
1. Σταματήστε το recon / το exposed control surface. Ο API server και ειδικά ο kubelet δεν πρέπει να είναι προσβάσιμοι από μη έμπιστα δίκτυα. Χρησιμοποιήστε firewall/security groups ώστε το 6443 να δέχεται μόνο από συγκεκριμένα δίκτυα και κλείστε τελείως το 10250 προς τα έξω. Managed clusters: προτιμήστε private endpoints για το control plane.
2. Σταματήστε το anonymous access. Ρυθμίστε τον API server με --anonymous-auth=false. Ελέγξτε σχολαστικά τα bindings προς system:anonymous και system:unauthenticated — δεν πρέπει να υπάρχει κανένα. Στον kubelet: --anonymous-auth=false και --authorization-mode=Webhook. Αυτό, μόνο του, «κόβει» δύο ολόκληρους δρόμους επίθεσης.
3. Σταματήστε την RBAC κατάχρηση με least-privilege. Καμία CI/CD ταυτότητα δεν πρέπει να έχει get/list secrets σε ολόκληρο namespace ή create pods. Δώστε στενά, ονομαστικά δικαιώματα (π.χ. patch σε συγκεκριμένο Deployment). Κάντε τακτικό audit με kubectl auth can-i --list για κάθε σημαντικό ServiceAccount. Απενεργοποιήστε το automount του SA token όπου δεν χρειάζεται (automountServiceAccountToken: false).
4. Σταματήστε τον privileged pod με PodSecurity admission. Ενεργοποιήστε το Pod Security Admission σε επίπεδο restricted (ή τουλάχιστον baseline) στους production namespaces. Αυτό απορρίπτει αυτόματα pods με privileged: true, hostPID, hostNetwork και hostPath. Για πιο λεπτομερή έλεγχο, χρησιμοποιήστε policy engine (Kyverno ή OPA Gatekeeper) που να μπλοκάρει hostPath mounts και επικίνδυνα capabilities.
5. Σταματήστε το lateral movement με Network Policies. Από προεπιλογή, κάθε pod μπορεί να μιλήσει σε κάθε pod. Εφαρμόστε default-deny NetworkPolicies και επιτρέψτε ρητά μόνο την απαραίτητη επικοινωνία. Έτσι, ακόμα κι αν πέσει ένα pod, δεν φτάνει εύκολα στο control plane ή στον kubelet.
6. Προστατέψτε τα secrets. Ενεργοποιήστε encryption-at-rest για τα etcd secrets. Ακόμα καλύτερα, μετακινήστε τα ευαίσθητα secrets σε εξωτερικό secrets manager (Vault, cloud KMS/Secrets Manager) με short-lived credentials, ώστε ένα get secrets να μην αρκεί.
7. Πιάστε τα λάθη πριν το deploy: image & config scanning. Βάλτε trivy config (ή kube-linter, checkov) στο CI/CD pipeline ως blocking gate. Ένα privileged: true δεν πρέπει ποτέ να περνά στο cluster χωρίς ρητή, τεκμηριωμένη εξαίρεση. Σαρώστε και τα images για CVEs.
8. Δείτε τι συμβαίνει: audit logging & runtime detection. Ενεργοποιήστε το API server audit logging και στείλτε το στο SIEM σας — η δημιουργία ενός privileged pod ή ένα exec σε pod είναι σήμα υψηλής προτεραιότητας. Προσθέστε runtime detection (Falco, eBPF sensors) που εντοπίζει container escape, chroot, ή απροσδόκητα mounts του host filesystem (T1611).
Αν εφαρμόσετε τα βήματα 2, 3 και 4, η συγκεκριμένη αλυσίδα σπάει σε τρία διαφορετικά σημεία — και αυτό είναι το ζητούμενο: defense in depth, ώστε ένα μόνο λάθος να μην αρκεί για κατάληψη.
Η γωνία NIS2 / DORA για cloud-native {#nis2}
Για τους οργανισμούς που εμπίπτουν στην NIS2 και τις χρηματοοικονομικές οντότητες υπό τον DORA, το Kubernetes δεν είναι απλώς τεχνική λεπτομέρεια — είναι μέρος της κρίσιμης υποδομής και του ICT risk management που απαιτεί ρητή διακυβέρνηση.
Η αλυσίδα που μόλις είδαμε αγγίζει άμεσα τις υποχρεώσεις συμμόρφωσης:
- Διαχείριση ευπαθειών και ρυθμίσεων. Τόσο η NIS2 όσο και ο DORA απαιτούν τεκμηριωμένη διαδικασία εντοπισμού και διόρθωσης αδυναμιών. Ένα εκτεθειμένο kubelet ή μια υπερβολικά προνομιακή RBAC είναι ακριβώς το είδος του ευρήματος που πρέπει να καταγράφεται, να προτεραιοποιείται και να αντιμετωπίζεται μέσα σε συγκεκριμένα χρονικά περιθώρια.
- Έλεγχος πρόσβασης και least privilege. Η αρχή του ελάχιστου προνομίου δεν είναι σύσταση· είναι απαίτηση. Ένας ServiceAccount CI/CD με δικαίωμα ανάγνωσης όλων των secrets είναι ευθεία παραβίαση αυτής της αρχής.
- Threat-led testing. Ο DORA εισάγει ρητά την έννοια του TLPT (Threat-Led Penetration Testing) για σημαντικές οντότητες. Η προσομοίωση μιας ρεαλιστικής αλυσίδας — όπως αυτή — είναι ακριβώς το είδος της απόδειξης ανθεκτικότητας που ζητούν οι ρυθμιστές.
- Logging & detection. Το API server audit logging και η runtime detection δεν είναι «nice to have»· είναι μέρος της ικανότητας incident detection & reporting που απαιτούν και τα δύο πλαίσια.
Με άλλα λόγια: η τεχνική άσκηση αυτού του άρθρου μεταφράζεται απευθείας σε regulatory evidence. Ένα δομημένο continuous exposure management πρόγραμμα και οι υπηρεσίες συμμόρφωσης NIS2/DORA μετατρέπουν αυτά τα ευρήματα σε τεκμηριωμένη, ελέγξιμη ασφάλεια.
Πότε δεν πρέπει να χρησιμοποιηθεί {#pote-oxi}
Οι τεχνικές αυτού του άρθρου είναι ισχυρές και, εκτός εργαστηρίου, επικίνδυνες και παράνομες χωρίς άδεια. Μερικοί σαφείς κανόνες:
- Ποτέ σε cluster που δεν σας ανήκει ή για το οποίο δεν έχετε ρητή, γραπτή εξουσιοδότηση. Το anonymous kubelet exec και η δημιουργία privileged pods σε ξένο cluster είναι σοβαρό ποινικό αδίκημα.
- Ποτέ σε παραγωγικό cluster χωρίς αυστηρά οριοθετημένο scope. Ένας privileged pod με
hostPath: /μπορεί να προκαλέσει πραγματική ζημιά στον node. - Ποτέ χωρίς cleanup. Στο lab μας, ο loopback stand-in τερματίζεται και τα manifests μένουν μόνο ως τεκμηρίωση· σε ένα πραγματικό engagement, κάθε attacker pod και κάθε token πρέπει να αφαιρείται και να τεκμηριώνεται.
- Ποτέ ως υποκατάστατο δομημένου προγράμματος ασφάλειας. Το να «τρέξεις kube-hunter» δεν είναι στρατηγική· είναι ένα εργαλείο μέσα σε μια ευρύτερη, τεκμηριωμένη διαδικασία.
Σύνοψη {#synopsi}
Είδαμε πώς μια σειρά από «διαχειρίσιμα» λάθη ρύθμισης — ένας ανοιχτός kubelet, ένας API server με anonymous access, μια γενναιόδωρη RBAC και η απουσία PodSecurity admission — αλυσιδώνονται σε πλήρη κατάληψη node και έκθεση όλων των secrets του cluster. Το πιο σημαντικό δίδαγμα είναι ότι κανένα βήμα δεν ήταν exploit: όλα ήταν ενέργειες που το cluster επέτρεπε. Γι’ αυτό τα cloud-native περιβάλλοντα χρειάζονται offensive validation, όχι μόνο scanning.
Δείξαμε επίσης, με πλήρη διαφάνεια, τι έτρεξε πραγματικά (nmap, curl, RBAC evaluation, base64 του flag) και τι είναι δηλωμένη ανακατασκευή (τα βήματα που απαιτούν ζωντανό kubelet). Και, κυρίως, δείξαμε ότι κάθε βήμα σταματά με συγκεκριμένους, εφαρμόσιμους ελέγχους — από --anonymous-auth=false και least-privilege RBAC, μέχρι PodSecurity admission, network policies, encryption-at-rest και runtime detection.
Ένα Kubernetes cluster δεν είναι ασφαλές ή ανασφαλές εκ φύσεως. Είναι ασφαλές όσο καλά το ρυθμίσατε — και η μόνη αξιόπιστη απόδειξη αυτού είναι να το δοκιμάσετε όπως θα το δοκίμαζε ένας πραγματικός επιτιθέμενος.
Από το εργαστήριο, στο δικό σας περιβάλλον {#cta}
Αυτό το εργαστήριο έδειξε μια αλυσίδα από exposed API σε node takeover σε ελεγχόμενο περιβάλλον. Στον πραγματικό κόσμο, το ερώτημα δεν είναι «αν» υπάρχουν τέτοιες αδυναμίες στα δικά σας clusters, αλλά «πού» και «πόσο βαθιά».
Η Audax Cybersecurity βοηθά οργανισμούς να απαντήσουν σε αυτό το ερώτημα με δομημένο, threat-led τρόπο:
- Στοχευμένο penetration testing σε web, API και cloud-native υποδομές.
- Adversary validation που αναπαράγει ρεαλιστικές αλυσίδες επίθεσης όπως αυτή.
- Συνεχές continuous exposure management και το Erevos AI, την ετήσια managed υπηρεσία CTEM που κρατά την επιφάνεια επίθεσης υπό διαρκή έλεγχο — με τεκμηριωμένη απόδειξη ανθεκτικότητας για NIS2 & DORA.
Human-led. Machine-scaled. Technically proven.
Αν θέλετε να αξιολογήσετε την πραγματική ανθεκτικότητα των Kubernetes περιβαλλόντων σας απέναντι σε σύγχρονες τεχνικές επίθεσης — και να μετατρέψετε τα ευρήματα σε τεκμηριωμένη συμμόρφωση NIS2/DORA — επισκεφθείτε το https://www.audax.gr για να μιλήσουμε.
Θέλετε συνεχή επικύρωση της ασφάλειάς σας — όχι έλεγχο μία φορά τον χρόνο;
Το Continuous Exposure Management της Audax ενοποιεί attack surface discovery, attack surface testing και παρακολούθηση αναδυόμενων απειλών σε έναν συνεχή, αποδεικτικό κύκλο — εκτελούμενο από τους certified offensive operators μας. Human-led. Technically proven. Ευθυγραμμισμένο με NIS2 & DORA.
Δείτε το Continuous Exposure Management →Χρειάζεστε Penetration Testing για τον οργανισμό σας;
Περιγράψτε το scope του ελέγχου μέσα από το δομημένο ερωτηματολόγιο και λάβετε εξατομικευμένη τεχνική & οικονομική προσφορά από την ομάδα Offensive Security της Audax. Χωρίς αυτόματη τιμή ή δέσμευση — η προσφορά αποστέλλεται μετά από τεχνική αξιολόγηση του scope.
Ζητήστε προσφορά Penetration Testing →