Write-upCloud Security

Kubernetes Güvenliği: RBAC, Pod Escape ve Sertleştirme

Container kaçışından cluster ele geçirmeye giden zincir ve onu kıran savunma katmanları

AL
AltaySecAltaySec Red Team
26 Ağustos 2026
10 dakika okuma
Özet

Kubernetes'te cluster ele geçirmenin baskın yolu bir CVE değil, yanlış yapılandırmadır: aşırı izinli RBAC, privileged/hostPath pod'ları, açık kubelet ve etcd servisleri ve ağ segmentasyonu eksikliği. Bu yazı tek bir container'dan node'a, oradan tüm cluster'a uzanan saldırı zincirini adım adım gösterir; ardından Pod Security Standards, least-privilege RBAC, seccomp/AppArmor ve default-deny NetworkPolicy ile bu zinciri hangi noktada kırabileceğinizi kanıtlarıyla ele alır.

Kubernetes Saldırı Yüzeyinin Anatomisi: Tek Pod’dan Cluster’a

Kubernetes güvenliğinde asıl tehlike, egzotik bir sıfır-gün açığı değil; art arda dizilen yanlış yapılandırmalardır. Saldırganın kalıbı neredeyse her zaman aynıdır: internete açık bir uygulama üzerinden bir container’a ayak basılır (initial access), o container’ın sahip olduğu servis hesabı token’ı veya yetkileriyle kontrol düzlemine (control plane) doğru yetki yükseltilir (privilege escalation), ardından node’a inilerek (container escape) ve ağ üzerinde yanal hareketle (lateral movement) tüm cluster ele geçirilir. Kubernetes dokümantasyonunun ve saha araştırmalarının (Aqua Security, Palo Alto Unit 42) ortak bulgusu nettir: bir kubelet’i veya etcd’yi savunmasız bırakan şey genellikle bir güvenlik yaması eksikliği değil, --anonymous-auth=true gibi bir bayrak ya da cluster-admin bağlanmış bir servis hesabıdır. Bu yazı, bu zinciri her halkasıyla ofansif olarak açıklar ve her halkayı kıran defansif kontrolü kanıtıyla verir.

Referans çerçeve olarak OWASP Kubernetes Top Ten (2022) listesini kullanacağız; çünkü saldırı zincirimizin her adımı bu risklerden birine denk gelir: K01 (Insecure Workload Configurations), K03 (Overly Permissive RBAC Configurations), K08 (Secrets Management Failures), K07 (Missing Network Segmentation Controls) ve K09 (Misconfigured Cluster Components).

Aşırı İzinli RBAC: escalate, bind, impersonate ve Pod Oluşturma Tuzağı

RBAC (Role-Based Access Control), Kubernetes’te kimin neye erişebileceğini belirleyen katmandır ve yetki yükseltmenin en verimli zeminidir. En sık görülen hata, “hızlı olsun” diye verilen wildcard’lardır — bir Role’de resources: ["*"] ve verbs: ["*"] görmek, pratikte o namespace’te cluster-admin vermek demektir.

Bir saldırgan, ele geçirdiği kimlikle ilk iş olarak yetkilerini haritalar:

# Mevcut kimliğin (veya token'ın) tüm izinlerini listele
kubectl auth can-i --list
# Belirli bir tehlikeli eylem mümkün mü?
kubectl auth can-i create pods --all-namespaces
kubectl auth can-i '*' '*'

Üç RBAC fiili (verb) özellikle kritiktir, çünkü doğrudan “yetki üreten” fiillerdir ve neredeyse hiçbir uygulamaya gerekli değildir:

  • escalate: Sahip olmadığınız izinleri bir Role/ClusterRole’e ekleyebilmenizi sağlar. Normalde Kubernetes, kendi yetkinizin üstünde bir Role yazmanızı engeller; escalate bu koruma korkuluğunu kaldırır. escalate + Role düzenleme yetkisi olan bir kimlik, kendisine keyfi izin atayabilir.
  • bind: Var olan bir ClusterRole’ü (örneğin cluster-admin) kendi hesabınıza bağlayabilmenizi sağlar.
  • impersonate: Başka bir kullanıcı, grup veya servis hesabı kimliğine bürünerek API çağrısı yapmanızı sağlar — etkili biçimde kimlik doğrulamayı atlar.

bind fiiline sahip bir kimliğin klasik yetki yükseltme hamlesi:

# Saldırgan kendi hesabını cluster-admin'e bağlar
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pwn
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: default
  namespace: default

Bunlara ek olarak, kısıtsız create pods yetkisi tek başına bir yetki yükseltme primitifidir: privileged bir pod ya da hostPath bağlayan bir pod oluşturabilen herkes, bir sonraki bölümdeki container kaçışını tetikleyebilir. Aynı şekilde pods/exec, pods/attach ve secrets üzerinde get/list yetkileri de doğrudan veri sızdırmaya veya çalışan yüksek-yetkili pod’lara komut enjekte etmeye açar. MITRE ATT&CK Container matrisi bu tekniği “Account Manipulation” olarak sınıflandırır: saldırgan bir RoleBinding/ClusterRoleBinding oluşturarak yetki ekler.

Container Kaçışı: Privileged Pod, hostPath ve hostPID ile Node’a İnmek

Container kaçışı (container escape), pod izolasyonunu delip altındaki node’un işletim sistemine erişmektir. Node’a root eriştiğinizde, o node üzerinde çalışan diğer tüm pod’ların secret’larını, kubelet kimliğini ve nihayetinde cluster’ı ele geçirebilirsiniz. Kaçışı mümkün kılan üç ayar, OWASP K01’in (Insecure Workload Configurations) somut karşılığıdır.

1) privileged: true — Container’ı neredeyse tüm çekirdek yeteneklerine ve host aygıtlarına erişimle çalıştırır. Böyle bir pod içinden host dosya sistemini mount edip chroot ile node’a geçmek mümkündür.

2) hostPath volume — Node’un dosya sistemindeki bir dizini doğrudan pod’a bağlar. / yolunu bağlamak, node’un tamamına okuma/yazma erişimi verir:

apiVersion: v1
kind: Pod
metadata:
  name: escape
spec:
  hostPID: true          # Node'un süreç ad-alanını paylaş
  containers:
  - name: escape
    image: alpine
    securityContext:
      privileged: true    # K01: tam ayrıcalık
    command: ["/bin/sh", "-c", "sleep 1d"]
    volumeMounts:
    - name: host
      mountPath: /host
  volumes:
  - name: host
    hostPath:
      path: /             # Node kök dizini pod içine bağlandı

Bu pod içine girildiğinde node’u ele geçirmek tek satırdır:

kubectl exec -it escape -- chroot /host /bin/bash
# Artık node üzerinde root'sunuz; kubelet client sertifikasını okuyun:
cat /var/lib/kubelet/pki/kubelet-client-current.pem

3) hostPID: true / hostNetwork / hostIPC — Host ad-alanlarını paylaşır. hostPID, node’daki tüm süreçleri /proc üzerinden görünür kılar; saldırgan yüksek-yetkili süreçlerin bellek/ortam değişkenlerinden token ve secret toplayabilir, hatta süreçlere enjeksiyon yapabilir.

Kritik dürüstlük notu: Bu tekniklerin hiçbiri bir “exploit” değildir — hepsi Kubernetes’in tasarım gereği desteklediği, ancak üretim iş yüklerinde gereksiz olan özelliklerdir. Savunma bu yüzden yamalama değil, bu özellikleri admission katmanında yasaklamaktır.

Servis Hesabı Token’larının Kötüye Kullanımı

Her pod, aksi belirtilmedikçe bir servis hesabı (ServiceAccount) token’ı ile doğar. Kubernetes v1.22’den itibaren bu token, TokenRequest API’si üzerinden alınan, süreli ve otomatik dönen (bound) bir token olarak projected volume ile şu yola bağlanır:

/var/run/secrets/kubernetes.io/serviceaccount/token

Sorun şu: automountServiceAccountToken varsayılan olarak açıktır. Bir web uygulamasını ele geçiren saldırgan, hiçbir ek zafiyete ihtiyaç duymadan bu token’ı okuyarak o servis hesabının tüm yetkilerini devralır. Eğer bu hesap aşırı yetkiliyse (örneğin secret’ları okuyabiliyor veya pod oluşturabiliyorsa), tek bir uygulama açığı cluster çapında erişime dönüşür (OWASP K03).

# Ele geçirilmiş pod içinden token ve CA ile doğrudan API'ye konuş
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
APISERVER=https://kubernetes.default.svc
curl -sk -H "Authorization: Bearer $TOKEN" \
  --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
  $APISERVER/api/v1/namespaces/default/secrets

Bir başka tehlikeli senaryo, kötü niyetli bir image’ın node üzerindeki yüksek-yetkili başka bir pod’un token’ını çalmasıdır (hostPID veya paylaşılan volume ile). Çalınan token, cluster dışından bile kullanılabildiği için — token cluster IP kısıtlaması taşımaz — saldırgan kendi makinesinden API’ye komut gönderebilir. Bunun kanonik tespiti audit log’dur: bir servis hesabına ait çağrıların beklenmedik kaynak IP’lerinden gelmesi, token hırsızlığının en net sinyalidir.

Kontrol Düzlemine Doğrudan Erişim: Kubelet API (10250) ve etcd (2379)

Bazı saldırılar RBAC’ı hiç uğraştırmaz; kontrol düzleminin altındaki servislere doğrudan konuşur (OWASP K09 — Misconfigured Cluster Components).

Kubelet API (TCP 10250): Her node’da çalışan kubelet, pod’ları listeleyen ve içlerinde komut çalıştıran bir HTTPS API sunar. Baskın risk bir CVE değil, iki bayraktır: --anonymous-auth=true ve --authorization-mode=AlwaysAllow. Bu ikisi birlikte kubelet’i kimlik doğrulamasız hale getirir. Aqua Security’nin taramaları internete açık on binlerce kubelet API’sinin bu şekilde erişilebilir olduğunu raporlamıştır.

# Anonim erişimle çalışan pod'ları listele
curl -sk https://<NODE_IP>:10250/runningpods/ | jq '.items[].metadata.name'
# Bir container içinde komut çalıştır (uzaktan kod çalıştırma)
curl -sk -X POST "https://<NODE_IP>:10250/run/<ns>/<pod>/<container>" -d "cmd=id"

etcd (TCP 2379): etcd, cluster’ın tüm durumunu tutan anahtar-değer deposudur — ConfigMap içerikleri, ortam değişkenleri ve tüm Secret nesneleri dahil. Kimlik doğrulamasız açık bırakılmış bir etcd, cluster’ın tamamının okunması ve değiştirilmesi demektir. Üstelik Kubernetes secret’ları varsayılan olarak şifrelenmez, yalnızca base64 ile kodlanır; API sunucusunda encryption-at-rest yapılandırılmamışsa, etcd’yi okuyan saldırgan tüm parolaları ve token’ları çözebilir. NCC Group’un araştırması, ele geçirilmiş bir etcd’nin cluster ve node’lar üzerinde tam kontrole nasıl dönüştüğünü ayrıntılandırır.

# Kimlik doğrulamasız etcd'den tüm secret'ları dök
etcdctl --endpoints=https://<IP>:2379 get / --prefix --keys-only | grep secrets
etcdctl --endpoints=https://<IP>:2379 get /registry/secrets/default/db-cred

Ağ Segmentasyonu Eksikliği ve Yanal Hareket

Çoğu CNI eklentisi (Calico, Cilium vb.) varsayılan olarak tüm pod-pod trafiğine izin verir. Yani hiçbir NetworkPolicy tanımlamadıysanız, ele geçirilen tek bir pod cluster içindeki her servise, her veritabanına, hatta kubelet ve etcd portlarına erişmeyi deneyebilir. OWASP bunu K07 (Missing Network Segmentation Controls) olarak listeler ve saha bulguları bunu üretim cluster’larındaki en yaygın açıklardan biri olarak gösterir.

Çözüm, default-deny duruşuyla başlayıp yalnızca meşru akışları allowlist’e almaktır. Aşağıdaki politika bir namespace’teki tüm gelen trafiği varsayılan olarak reddeder:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: uygulama
spec:
  podSelector: {}          # Namespace'teki TÜM pod'lar
  policyTypes: ["Ingress"]
  # ingress kuralı yok = her şey reddedilir

Kritik bir tuzak: default-deny egress uygularsanız, DNS’i açıkça izinlemezseniz pod’lar CoreDNS’e (kube-system, UDP/TCP 53) ulaşamaz ve tüm isim çözümlemesi bozulur. Bu yüzden egress politikalarında DNS istisnasını daima ekleyin. Doğru uygulanmış NetworkPolicy, ele geçirilmiş bir pod’u yalnızca gerçekten ihtiyaç duyduğu iki-üç akışla sınırlar — bu, tüm cluster’ı tarayabilen bir dayanak ile yalnızca kendi bağımlılıklarına konuşabilen bir dayanak arasındaki farktır.

Savunma Mimarisi: Katmanları Üst Üste Koymak

Tek bir kontrol yeterli değildir; savunma derinliği (defense in depth) her saldırı halkasını farklı bir katmanda kırar. Aşağıdaki dört katman birlikte uygulanmalıdır.

1) Pod Security Standards (PSS) ile admission kontrolü. Kubernetes 1.25’te (Ağustos 2022) stabil (GA) hale gelen Pod Security Admission, namespace düzeyinde üç profil dayatır: privileged, baseline, restricted. Baseline, en bilinen kaçış vektörlerini engeller — privileged container yok, host ad-alanları (hostPID/hostNetwork/hostIPC) yok, güvenli listede olmayan hostPath yok. Restricted bunun üstüne çıkar: container’lar root olmayan kullanıcıyla çalışmalı, allowPrivilegeEscalation: false olmalı, tüm capability’ler düşürülmeli ve seccomp profili ayarlanmalı. Namespace’e etiketle uygulanır:

apiVersion: v1
kind: Namespace
metadata:
  name: uygulama
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted

2) restricted uyumlu securityContext. Her pod/container şu şablona yakınsamalıdır:

securityContext:
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  seccompProfile:
    type: RuntimeDefault      # tehlikeli syscall'ları kısıtlar (runtime varsayılan profili)
  capabilities:
    drop: ["ALL"]
  readOnlyRootFilesystem: true

RuntimeDefault seccomp profili, container runtime’ın (containerd/CRI-O) yerleşik profilini kullanarak tehlikeli çekirdek çağrılarını engeller; bu, restricted profiline geçişte en sık atlanan gereksinimdir. Daha ince kontrol için AppArmor/SELinux profilleri de node düzeyinde dayatılmalıdır.

3) Least-privilege RBAC. Wildcard’ı yasak sayın. Bir uygulamanın gerçekten ihtiyaç duyduğu minimal Role şuna benzemeli — belirli kaynak, belirli fiil, mümkünse resourceNames ile daraltılmış:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: uygulama
  name: configmap-okuyucu
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["app-config"]
  verbs: ["get", "list"]

escalate, bind, impersonate fiillerini ve cluster-admin bağlamalarını asla rutin iş yüklerine vermeyin. automountServiceAccountToken: false ile token’ları varsayılan olarak enjekte etmeyi kapatın; token’a ihtiyaç duyan pod’da açıkça açın. Cluster genelinde create pods gibi tehlikeli izinleri OPA/Gatekeeper veya Kyverno gibi politika motorlarıyla bir admission kapısına bağlayarak (OWASP K04 — Lack of Centralized Policy Enforcement) sınırlayın.

4) Kontrol düzlemi ve ağ sertleştirmesi. Kubelet’te --anonymous-auth=false ve --authorization-mode=Webhook; etcd’de istemci mTLS sertifika doğrulaması ve ağ izolasyonu; API sunucusunda EncryptionConfiguration ile secret’ların KMS/aescbc ile şifrelenmesi (K08 — Secrets Management Failures). Tüm bunların üstüne default-deny NetworkPolicy ve kapsamlı audit log (K05 — Inadequate Logging and Monitoring) gelir.

Yanlış Yapılandırma × Risk × Sertleştirme

Yanlış Yapılandırma Saldırı Sonucu / Risk Sertleştirme Kontrolü
privileged: true Container kaçışı, node’da root PSS Baseline/Restricted ile privileged reddi
hostPath: / mount Node dosya sistemine yazma, kubelet kimlik hırsızlığı hostPath yasağı (Baseline), gerekiyorsa readOnly + dar yol
hostPID/hostNetwork/hostIPC /proc üzerinden token toplama, süreç enjeksiyonu Host ad-alanı yasağı (Baseline)
allowPrivilegeEscalation: true, seccomp yok setuid/syscall istismarı Restricted: false + seccompProfile: RuntimeDefault
RBAC * / cluster-admin bağlaması Cluster ele geçirme Least-privilege Role, wildcard yasağı, düzenli auth can-i denetimi
escalate/bind/impersonate fiilleri Keyfi yetki verme, kimliğe bürünme Bu fiilleri iş yüklerine hiç vermeme
Kısıtsız create pods / pods/exec Privileged pod ile kaçış, komut enjeksiyonu Admission policy (Kyverno/OPA), namespace izolasyonu
automountServiceAccountToken: true + aşırı yetkili SA Token hırsızlığı → API erişimi automount: false, bound + minimal-yetkili SA
Kubelet anonymous-auth=true + AlwaysAllow Uzaktan komut çalıştırma (10250) anonymous-auth=false, Webhook authz, ağ/FW kısıtı
etcd 2379 kimlik doğrulamasız Tüm secret’ların dökümü İstemci mTLS, ağ izolasyonu, encryption-at-rest
NetworkPolicy yok Serbest yanal hareket Default-deny + explicit allowlist (DNS istisnasıyla)
Secret’lar sadece base64 etcd/API okumasıyla açığa çıkma EncryptionConfiguration (KMS/aescbc)

Operasyonel Özet: Zinciri Nerede Kırarsınız?

Kubernetes güvenliğinin özü, tek bir “sihirli” kontrol değil, saldırı zincirinin her halkasını farklı bir katmanda kesmektir. İlk erişim kaçınılmaz kabul edilir; asıl kazanç, o ilk container’ı bir çıkmaz sokağa hapsetmektir. Pod Security Standards restricted container kaçışını, least-privilege RBAC + automount: false token’la yetki yükseltmeyi, kubelet/etcd sertleştirmesi kontrol düzlemi atlamasını ve default-deny NetworkPolicy yanal hareketi keser. Bu katmanlar tek tek de değer taşır; ama birlikte uygulandığında, tek bir uygulama açığının tüm cluster’ı düşürdüğü o klasik zinciri fiilen imkânsız hale getirir.

Denetime bugün başlamak isteyen ekipler için üç somut adım: (1) kubectl auth can-i --list ile aşırı yetkili servis hesaplarını ve escalate/bind/impersonate taşıyan Role’leri çıkarın; (2) tüm üretim namespace’lerine pod-security.kubernetes.io/enforce: restricted etiketini önce warn modunda deneyip sonra dayatın; (3) her namespace’e bir default-deny NetworkPolicy ekleyip meşru akışları tek tek açın. Bu üç adım, OWASP Kubernetes Top Ten’in en yüksek etkili risklerini (K01, K03, K07) tek hamlede kapatmaya başlar.

AL
AltaySec
AltaySec Red Team
AltaySec Arşiv topluluğuna katkı veren yazar. Türkçe siber güvenlik bilgi tabanını birlikte büyütüyoruz.

Sen de yaz, arşivde yerini al

AltaySec Arşiv'e katkı ver — uzmanlığını Türkçe siber güvenlik literatürüne kat.

Yazar Ol