İçeriğe geç
Sedat Özdemir
Yazılar

cloud-native

Kube-apiserver'ı İnternete Açtığın Gün, Cluster'ın Tapusunu Hacker'a Devretmişsindir

Kubernetes dünyasında default ayarlar genellikle felaket getirir. RBAC'tan Network Policy'ye, siber saldırganların iştahını kabartan o kritik boşlukları ve savunma hattını nasıl kuracağımızı konuşuyoruz.

Sedat Özdemir
· 4 dk okuma

Kube-apiserver loglarında 401 veya 403 hatalarını görmüyorsan, ya kimse seni aramıyor ya da içerideler ama sen izlemiyorsun. Kubernetes (K8s) dünyasına hoş geldin; burası orkestrasyonun zirvesi olduğu kadar, yanlış bir 'indentation' ile tüm altyapıyı teslim edebileceğin bir mayın tarlasıdır.

Bir sabah uyandığında kubectl get pods -A yazdığında tanımadığın 'xmrig' podlarını görmeni istemiyorsan, bu işin kitabını değil, sahadaki kirli gerçeklerini konuşmamız lazım. testCompany bünyesinde gördüğümüz senaryolardan yola çıkarak, cluster'ın ciğerine kadar sızan o zafiyetleri ve onları nasıl yamayacağımızı masaya yatıralım.

RBAC: Yetkiyi Dağıtırken Cluster'ı Dağıtmak

RBAC (Role-Based Access Control), K8s güvenliğinin kalbidir ama çoğunlukla en çok ihmal edilen kısmıdır. Genelde şöyle olur: Bir developer bir tool kurmak ister, izin hataları alır, 'aman uğraşmayalım' denir ve o meşhur cluster-admin rolü o ServiceAccount'a (SA) şak diye verilir.

Bak dostum, bir saldırgan olarak içeri sızdığımda ilk baktığım şey, üzerinde bulunduğum podun /var/run/secrets/kubernetes.io/serviceaccount/token dosyasındaki yetkileridir. Eğer o token ile list secrets yapabiliyorsam, o cluster artık benimdir.

Zararsızlaştırılmış (defanged) bir RBAC faciası örneği:

# BU BİR FELAKET REÇETESİDİR
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: dev-user-binding
subjects:
- kind: User
  name: developer-x
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin # Bir developer neden tüm cluster'ın patronu olsun?
  apiGroup: rbac.authorization.k8s.io

Ne yapmalısın? 'Least Privilege' prensibi burada hayat kurtarır. Role ve RoleBinding kullan, ClusterRole sadece global işler için kalsın. ServiceAccount'ların default olarak token mount etmesini engelle: automountServiceAccountToken: false.

Secrets: Base64 Bir Şifreleme Yöntemi Değildir!

Bunu hala söylüyoruz ya, bazen gerçekten hayret ediyorum. K8s Secret objeleri varsayılan olarak etcd üzerinde şifrelenmeden tutulur. Sadece Base64 ile encode edilirler. Yani birisi etcd yedeğini ele geçirirse veya API server'a yetkisiz erişirse, veritabanı şifrelerin, API key'lerin hepsi havada uçuşur.

# Bir secret'ı 'çözmek' bu kadar basittir:
echo "Z3V2ZW5saWRlZ2lsc2luCg==" | base64 --decode

Çözüm:

  1. Encryption at Rest: API Server konfigürasyonuna EncryptionConfiguration ekleyerek etcd üzerindeki veriyi şifrele.
  2. External Secrets / Vault: Secret'ları cluster dışında (HashiCorp Vault, AWS Secrets Manager vb.) tutan operatörler kullan.

Pod Escape: Konteynerden Host'a Atlamak

Bir podun içindeyim, kısıtlıyım ama özgür olmak istiyorum. Eğer pod privileged: true ile çalışıyorsa veya host path'leri mount edilmişse, o podun içinden host işletim sistemine zıplamak çocuk oyuncağı.

Saldırganın iştahını kabartan o pod tanımı:

apiVersion: v1
kind: Pod
metadata:
  name: host-kafan-karisik-pod
spec:
  containers:
  - name: exploit-container
    image: alpine
    securityContext:
      privileged: true # Root yetkisiyle host cihazlarına erişim sağlar
    volumeMounts:
    - mountPath: /host-fs
      name: root-mount
  volumes:
  - name: root-mount
    hostPath:
      path: / # Tüm ana işletim sistemi dosyaları burada!

Burada /host-fs/etc/shadow dosyasını okuyup host'un şifrelerini kırmaya başlayabilirim.

Savunma:

  • Pod Security Admission (PSA) kullan. privileged, hostPath, hostNetwork gibi özelliklere 'Baseline' veya 'Restricted' politikalarıyla dur de.
  • Container'ları asla root user ile çalıştırma. Dockerfile içinde USER 1001 demeyi alışkanlık haline getir.

Network Policies: Varsayılan Olarak 'Açık Büfe'

Kubernetes ağ yapısı varsayılan olarak "düzdür" (flat network). Yani Pod A, Pod B ile herhangi bir kısıtlama olmadan konuşabilir. Eğer mikroservis mimarinde bir frontend podunu hacklersem, oradan direkt olarak arkadaki veritabanı poduna 10.x.x.x IP'si üzerinden saldırabilirim. Buna siber güvenlikte "Lateral Movement" (Yanal Hareket) diyoruz.

Varsayılan olarak her şeyi kapatıp, sadece gerekenlere izin vermelisin.

# Tüm ingress trafiği reddeden 'Default Deny' politikası
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Bu politikayı uyguladığın an cluster sessizliğe bürünür. Sonra tek tek sadece frontend -> backend gibi izinleri tanımlamalısın.

Image Güvenliği: İçeride Truva Atı Beslemeyin

Public bir imajı (Örn: node:latest) çekip kullanmak büyük bir risk. O imajın içinde ne var? Hangi CVE (Common Vulnerabilities and Exposures) zafiyetlerini barındırıyor? Hatta daha kötüsü, o imaj gerçekten o kişi tarafından mı yüklendi?

Stratejin şu olmalı:

  • Kendi private registry'ni kullan (Harbor gibi).
  • Imajları mutlaka scan et (Trivy, Grype).
  • Imajları imzala (Cosign) ve sadece imzalı imajların çalışmasına izin ver (Admission Controllers).

API Server'ı Zırhlamak

Başlangıçtaki o sert girişe geri dönelim. Kube-apiserver senin her şeyindir. Onu asla internete doğrudan açma. IP whitelist, VPN veya Cloud Provider'ın private endpoint özelliklerini kullan.

Eğer bir gün curl -k https://127.0.0.1:6443/api/v1/namespaces/default/secrets komutunu dışarıdan biri (unauthenticated) çalıştırıp veri alabiliyorsa, o gün senin siber güvenlik kariyerindeki en kötü gündür.

Gerçek Hayattan Bir 'Hardening' Listesi

Okumayı sevmeyen, aksiyon isteyenler için hızlıca özetliyorum:

  1. Node'ları sıkılaştır: SSH'ı kapat veya kısıtla, OS hardening (CIS Benchmarks) uygula.
  2. Audit Logs: K8s audit loglarını mutlaka bir SIEM çözümüne (Splunk, ELK) aktar. Kim, ne zaman, hangi komutu çalıştırdı bilmek zorundasın.
  3. Runtime Security: Falco gibi bir araç kur. Bir pod içinde beklenmedik bir binary (örneğin apt-get veya nmap) çalıştırıldığında anında alarmın çalsın.
  4. Liveness/Readiness Probes: Sadece uygulama sağlığı için değil, DoS saldırılarını hafifletmek için de doğru konfigüre et.

K8s güvenliği bir varış noktası değil, bir yolculuktur. testCompany'de biz her gün yeni bir vektör keşfedip onu nasıl kapatırız diye kafa yoruyoruz. Sen de bugün cluster'ındaki bir podun yetkilerini kontrol ederek başla. Belki de o çok güvendiğin 'namespace' izolasyonu aslında bir illüzyondan ibarettir.

Unutma, sistemin en zayıf halkası, senin 'bir şey olmaz' dediğin o küçük ayardır. Güvenli kal!

İlgili yazılar