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

container-security

YAML Dosyaları Arasında Kaybolmak: Kubernetes’te Güvenliği 'Default' Ayarlara Bırakmanın Bedeli

Kubernetes güvenliğini sadece bir YAML dosyasından ibaret sananlar için acı gerçekler: RBAC facialarından, konteyner kaçışlarına kadar sahadan süzülen tecrübeler.

Sedat Özdemir
· 4 dk okuma

Cluster admin yetkisi verdiğin o stajyerin, tek bir kubectl komutuyla tüm production ortamını 'yanlışlıkla' sildiğini fark ettiğinde içtiğin o acı kahvenin tadını hatırlıyor musun? Eğer henüz böyle bir kahve içmediysen, ya çok şanslısın ya da Kubernetes (K8s) dünyasında 'default' ayarların yarattığı o sahte güvenlik algısına kapılmışsın demektir.

Selam millet, ben Sedat. Bugün biraz 'orchestration' dünyasının karanlık dehlizlerine, yani K8s güvenliğine gireceğiz. Red Team tarafında işimiz sadece sızmak değil, aynı zamanda o sızdığımız yolların neden açık olduğunu anlatmak. K8s söz konusu olduğunda genelde 'Kurduk, çalışıyor, hadi gidelim' mantığı hakim. Ama o 'çalışıyor' dediğin sistem, aslında içeri sızan bir saldırgan için muazzam bir oyun alanı sunuyor olabilir. Gel, testCompany'deki simülasyonlarımızdan ve sahadaki tecrübelerden yola çıkarak bu canavarı nasıl biraz daha evcilleştiririz, ona bakalım.

RBAC: 'Herkes Admin, Herkes Kral' Mantığının Sonu

K8s kurulumu bittiğinde ilk yapılan hata genellikle herkese cluster-admin rolü dağıtmaktır. Çünkü neden? Kimse 'Forbidden' hatası alıp işinden geri kalmasın. Ama unuttuğumuz bir şey var: RBAC (Role-Based Access Control) sadece insanlar için değil, ServiceAccount’lar için de geçerli. Bir saldırganın pod içine sızdığını düşün. Eğer o pod'un kullandığı ServiceAccount gereksiz yere geniş yetkilere sahipse, saldırgan cluster içinde yatayda değil, direkt dikeyde hareket eder.

Bakın, şu YAML dosyası aslında bir 'felaket reçetesi'dir:

# BU BİR KÖTÜ ÖRNEKTİR - Lütfen production ortamına yaklaştırmayın!
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: default-sa-admin-binding
subjects:
- kind: ServiceAccount
  name: default
  namespace: dev-team
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Burada ne mi oluyor? dev-team namespace'indeki 'default' service account'una tüm cluster üzerinde Tanrı yetkisi verdik. Eğer bir saldırgan bu namespace'de çalışan basit bir web uygulamasını hacklerse, artık cluster'ın anahtarlarına sahip demektir.

Ne yapmalı? En küçük yetki prensibi (Least Privilege). Pod'un sadece ihtiyacı olan API'lara erişimi olsun. Hatta mümkünse automountServiceAccountToken: false diyerek o token'ı pod'un içine hiç koymayın. Lazım değilse neden orada dursun?

Konteyner Kaçışları ve Privileged Pod’lar

Şimdi biraz daha teknik bir noktaya parmak basalım: privileged: true. Bu ayar, konteynerin host makinedeki neredeyse tüm yetkilere sahip olması demektir. Red Team operasyonlarında bir pod içinde bu ayarın açık olduğunu görürsek, o akşam eve erken gideriz çünkü host makineye sızmak saniyelerimizi alır.

Örnek bir 'tehlikeli' pod konfigürasyonu şöyledir:

apiVersion: v1
kind: Pod
metadata:
  name: tehlikeli-pod
spec:
  containers:
  - name: exploit-container
    image: example.com/security-tool:latest
    securityContext:
      privileged: true # İşte burada patlıyoruz.

Bir saldırgan, bu yetkiyle host üzerindeki diskleri mount edebilir, host'un network trafiğini dinleyebilir. Bizim testCompany simülasyonlarında gördüğümüz en büyük açıklar genelde bu 'kolaylık olsun' diye açılan kapılardan çıkıyor.

Doğru yaklaşım: SecurityContext kullanarak yetkileri kısıtlamak. allowPrivilegeEscalation: false ve runAsNonRoot: true parametreleri sizin en yakın dostunuz olsun. Pod root olarak çalışmak zorunda mı? Muhtemelen hayır.

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

K8s'te network yapısı varsayılan olarak şöyledir: Herkes herkesle konuşabilir. Frontend pod'u gidip direkt DB pod'una SQL injection denemesi yapabilir mi? Evet. Eğer bir Network Policy tanımlamadıysanız, cluster'ınız bir 'açık büfe' gibidir.

Saldırganın lateral movement (yatay hareket) kabiliyetini kısıtlamak için 'Default Deny' kuralı şarttır. Önce her şeyi kapatın, sonra sadece ihtiyacınız olan kapıları açın. Şöyle bir başlangıç yapabilirsiniz:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Bu kuralı uyguladığınız an her şey durur. Sonra tek tek 'A pod'u B pod'una 80 portundan gitsin' diye izinleri tanımlarsınız. Zahmetli mi? Evet. Güvenli mi? Kesinlikle.

Secrets Management: Base64 Şifreleme Değildir!

Bunu hala söylemek zorunda kaldığım için bazen kendimi eski bir plak gibi hissediyorum ama: K8s Secret'ları şifreli değildir, sadece Base64 ile encode edilmiştir. Yani birisi etcd veritabanına erişirse veya kubectl get secrets -o yaml yaparsa, şifrelerinizi kabak gibi görür.

Saldırı senaryosunu canlandıralım: echo "Z2l6bGktc2lmcmU=" | base64 --decode -> Sonuç: gizli-sifre.

K8s içindeki secret yönetimini 'Hardening' etmek için:

  1. Encryption at Rest: etcd'deki verilerin diskte şifrelenmesini sağlayın.
  2. External Secrets: Şifreleri K8s içinde değil, HashiCorp Vault veya AWS Secrets Manager gibi profesyonel araçlarda tutun ve K8s'e 'inject' edin.

Cloud Metadata Service (IMDS) Tehlikesi

Eğer K8s cluster'ınız AWS, GCP veya Azure gibi bir bulut sağlayıcı üzerindeyse, saldırganların ilk bakacağı yer 169.254.169.254 IP'si olacaktır. Bu IP, o makinenin kimlik bilgilerini (IAM rolleri vb.) verir. Bir pod'dan bu IP'ye erişebilen saldırgan, tüm cloud altyapınızı ele geçirebilir.

Bunu engellemek için Network Policy ile bu IP'ye erişimi mutlaka bloklayın. Testlerimizde, birçok şirketin cluster içinden kendi cloud provider'ının metadata servisine erişimi açık bıraktığını ve bunun üzerinden 'cloud escape' yapılabildiğini defalarca gördük.

Son Bir Kaç Tavsiye

Kubernetes güvenliği bir varış noktası değil, bir yolculuk. Bugün her şeyi kapattım deseniz bile yarın yeni bir CVE (Common Vulnerabilities and Exposures) çıkabilir. O yüzden:

  • Görüntüleri (Images) düzenli olarak tarayın.
  • Sadece güvendiğiniz registry'lerden (örneğin example.com/internal-repo) image çekilmesine izin verin.
  • Admission Controller'ları (OPA Gatekeeper, Kyverno gibi) kullanarak cluster kurallarını otomatiğe bağlayın. 'Kimse privileged pod açamasın' kuralını bir kez yazın, sistem otomatik engellesin.

K8s kompleks bir yapı, evet. Ama bu karmaşıklık içinde kaybolup kapıları açık bırakmak, sadece saldırganların işine yarar. Kendine bir iyilik yap, bugün cluster'ındaki yetkileri ve network akışlarını bir gözden geçir. Bakalım kaç tane 'kapının üzerinde unutulmuş anahtar' bulacaksın?

Görüşmek üzere, güvenli kalın!

İlgili yazılar