Kubernetes v1.37: emptyDir ve Bind Mount Sertleştirmesi

Kubernetes v1.37’de bindMountOptions ve emptyDir için mode ayarlarıyla noexec/nosuid ve sticky bit gibi Linux mekanizmaları doğrudan Pod manifestinden uygulanabiliyor. Özellikler v1.37’de Alpha aşamasında.

Kubernetes v1.37’de konteyner depolamasını sertleştiren iki yeni alan var: volume mount’lara uygulanan bindMountOptions ve emptyDir hacimleri için mode. Yazılabilir bir hacimden rastgele ikili dosya çalıştırılmasını engellemek ya da aynı Pod içindeki bir konteynerin diğerinin dosyalarını silmesini önlemek için artık init container ve chmod gibi dolaylı yöntemlere gerek yok, politika doğrudan Pod manifestinde tanımlanıyor. Her iki özellik de v1.37’de Alpha aşamasında.

Arka plan: Linux’ta mount bayrakları ve sticky bit

Yeni alanların ne yaptığı, altlarındaki Linux mekanizmalarına bakınca netleşiyor. Linux bir dizini mount ya da remount ettiğinde, Virtual File System (VFS) bayrakları o dosya sisteminde hangi işlemlere izin verileceğini belirler:

  • noexec: Mount edilen dosya sistemindeki ikili dosyaların doğrudan çalıştırılmasına izin verilmez.
  • nosuid: set-user-identifier ve set-group-identifier bitlerinin etkili olması engellenir.
  • nodev: Dosya sistemindeki karakter veya blok özel aygıtları yorumlanmaz.

İkinci mekanizma klasik Unix izinleri. Owner, Group ve Others kapsamlarındaki okuma/yazma/çalıştırma bitlerinin (0755, 0777 gibi) yanında Linux sticky bit‘i de destekler, 01777 modunda olduğu gibi. Bir dizine uygulandığında sticky bit, o dizindeki bir dosyanın yalnızca dosyanın sahibi veya root tarafından silinebilmesini ya da yeniden adlandırılabilmesini sağlar. /tmp gibi paylaşılan yazılabilir dizinlerde bu davranış temel bir gereklilik.

Neden ihtiyaç duyuldu?

Varsayılan davranışta hacimler, container runtime ve kubelet tarafından konteynere noexec, nosuid veya nodev bayrakları olmadan bind mount ediliyordu. Pratikte bu şu demekti: readOnlyRootFilesystem: true ayarlanmış olsa bile ele geçirilmiş bir süreç yazılabilir herhangi bir hacmi (emptyDir, PersistentVolume vb.) kullanarak dosya indirebilir, chmod +x ile çalıştırılabilir hale getirebilir ve çalıştırabilirdi. noexec, nodev ve nosuid desteğiyle birlikte güvenlik kıyaslamalarına ve kurum politikalarına uygun sertleştirme artık Kubernetes’in kendi API’siyle yapılabiliyor.

Boşluk en çok emptyDir tarafında görünüyordu, çünkü en yaygın kullanılan yazılabilir hacim türü bu ve birden fazla güvenlik bulgusuna konu oldu:

  • Issue #48912: emptyDir üzerinde mount seçeneği ayarlanamaması bir denetimde güvenlik boşluğu olarak işaretlenmiş, ancak bugüne kadar çözülmemişti.
  • Issue #119627: Kubernetes 1.24 Güvenlik Denetimi (Bulgu NCC-E003660-7HM) kapsamında dış denetçiler, emptyDir‘ın noexec ile mount edilememesini açıkça bir güvenlik eksiği olarak not etti.

Aynı eksik aslında tüm hacim türleri için geçerliydi. PersistentVolume nesnelerinde mountOptions alanı var, ama bunlar CSI sürücüsünün node üzerinde uyguladığı dosya sistemi düzeyi bayraklar; konteyner içindeki bind mount bayraklarına güvenilir biçimde dönüşmüyorlar. Yani container runtime’ın oluşturduğu bind mount üzerinde noexec, nosuid veya nodev ayarlamanın hiçbir hacim türü için yolu yoktu.

emptyDir ayrıca dizinleri sabit kodlanmış 0777 moduyla oluşturuyordu. Yani hacmi keşfedebilen herhangi bir süreç, dosyaları kimin oluşturduğundan bağımsız olarak okuyabiliyor, yazabiliyor, silebiliyordu. Farklı bir erişim modu ayarlamak için init container kullanmak mümkündü, hala da mümkün, ama bu yöntem hem daha karmaşık hem de uyumluluk açısından doğrulaması zor.

Somut sorunlar da buradan çıkıyordu. Aynı emptyDir‘ı paylaşan çok konteynerli Pod’larda bir konteynerin diğerinin dosyalarını silmesi engellenemiyordu. Sticky bit (01777) tam olarak bunu çözer, ama yerleşik bir ayar yolu yoktu. Bazı uygulamalar ve güvenlik çerçeveleri /tmp dizinlerinin 01777 modunda olmasını bekliyor, bu da init container veya alternatif hacim türleri gerektiriyordu. Daha sıkı izinler isteyen platform ekipleri, örneğin yalnızca owner ve group için 0750, chmod çalıştıran init container’lara mecburdu.

Pratikteki kullanım senaryoları

  • Yazılabilir mount’larda ayrıcalık yükseltmeyi engellemek: Geçici çalışma alanı hacimlerini (emptyDir ya da /tmp mount’ları) nosuid ve noexec ile mount ederseniz, uygulama ele geçirilse ve kötü niyetli bir yük indirilse bile o yük çalıştırılamaz, node üzerinde ayrıcalık yükseltilemez.
  • Çok konteynerli Pod’larda paylaşılan scratch alanını korumak: CI/CD Pod’larında builder konteyneri ile sidecar logger aynı çalışma alanını paylaşabilir. emptyDir üzerinde mode: 01777 ayarlandığında alan klasik Unix /tmp gibi davranır: Her konteyner bağımsız yazabilir, ancak birinde ele geçirilmiş bir süreç diğerinin ürettiği build çıktılarını silemez.
  • En az ayrıcalık ilkesini uygulamak: Veritabanı Pod’larında emptyDir‘a mode: 0750 verilerek geçici depolamaya yalnızca ilgili kullanıcı ve grup erişir; aynı Pod’daki diğer süreçlere ve sidecar’lara erişim açıkça kapanır.

Örnek manifestler

Her iki özellik de v1.37’de Alpha feature gate arkasında. Kullanmak için API server ve kubelet üzerinde VolumeBindMountOptions ve EmptyDirVolumeMode kapılarını etkinleştirmeniz gerekiyor.

Bind mount seçeneklerini zorunlu kılmak

Aşağıdaki Pod, /tmp yoluna bir emptyDir hacmini bindMountOptions: [noexec, nosuid] ile mount ediyor:

apiVersion: v1
kind: Pod
metadata:
name: hardened-bindmount-pod
namespace: default
spec:
os:
name: linux
containers:
- name: hardened-app
image: alpine:latest
command: ["sleep", "3600"]
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: temp-storage
mountPath: /tmp
bindMountOptions:
- noexec
- nosuid
volumes:
- name: temp-storage
emptyDir: {}

emptyDir izin modu ve sticky bit

Bu Pod ise mode: 01777 ile konteynerler arasında standart Unix /tmp sticky bit korumasını uyguluyor:

apiVersion: v1
kind: Pod
metadata:
name: hardened-emptydir-pod
namespace: default
spec:
os:
name: linux
containers:
- name: app-container
image: alpine:latest
command: ["sleep", "3600"]
volumeMounts:
- name: shared-tmp
mountPath: /tmp
volumes:
- name: shared-tmp
emptyDir:
mode: 01777

Kısıtlamaların gerçekten uygulandığını doğrulamak

Özelliklerin etkin olduğunu görmenin en doğrudan yolu, kubectl exec ile konteynere girip engellenen işlemleri denemek.

noexec doğrulaması

# 1. Pod'a exec ol
kubectl exec -it hardened-bindmount-pod -- sh
# 2. Mount edilmiş hacimde çalıştırılabilir bir script oluştur
cd /tmp
echo '#!/bin/sh' > test.sh
echo 'echo "Executing untrusted code..."' >> test.sh
chmod +x test.sh
# 3. Scripti çalıştırmayı dene
./test.sh

Beklenen çıktı: sh:./test.sh: Permission denied

Dosya çalıştırılabilir olarak oluşturulsa bile kernel çalıştırmayı reddeder, çünkü MS_NOEXEC bind mount seviyesinde uygulanır.

Sticky bit doğrulaması

# 1. Pod'a exec ol
kubectl exec -it hardened-emptydir-pod -- sh
# 2. /tmp üzerindeki dizin izinlerini kontrol et
ls -ld /tmp
# Çıktı: drwxrwxrwt 2 root root... /tmp ('t' sticky bit'i gösterir)
# 3. guest kullanıcısı olarak bir dosya oluştur
su -s /bin/sh -c "touch /tmp/guest_file" guest
# 4. nobody kullanıcısı olarak bu dosyayı silmeyi dene
su -s /bin/sh -c "rm /tmp/guest_file" nobody

Beklenen çıktı: rm: can't remove '/tmp/guest_file': Operation not permitted

Sticky bit (01777) dosya silme yetkisini yalnızca dosyanın sahibine bıraktığı için kernel işlemi engeller.

Kullanmadan önce bilinmesi gerekenler

  • Varsayılanlar değişmedi: bindMountOptions belirtmez ya da emptyDir için mode ayarlamazsanız eskisiyle birebir aynı varsayılan davranışı (örneğin 0777 izinleri) alırsınız.
  • Geniş hacim desteği: bindMountOptions; emptyDir, PersistentVolume, CSI hacimleri, projected volume, ConfigMap ve Secret gibi türlerle çalışır. Tek istisna, açıkça desteklenmeyen image volume’lar. mode alanı ise tüm emptyDir medium türlerinde geçerli: varsayılan (disk tabanlı), Memory (tmpfs) ve HugePages.
  • Runtime yetenekleri önemli (yalnızca bindMountOptions için): Container runtime’ın CRI mount_options alanını desteklemesi ve bunu runtimeFeatures üzerinden duyurması gerekir. Scheduler, node declared features bilgisini kullanarak Pod’ları uyumsuz node’lara yerleştirmekten kaçınır; Pod yine de böyle bir node’a ulaşırsa kubelet onu reddeder. Sessizce devre dışı kalma (silent degradation) yoktur. emptyDir için mode kullanmaksa runtime desteği gerektirmez.
  • PV mountOptions ile aynı şey değil: PersistentVolume mountOptions alanı, CSI sürücüsü aracılığıyla depolama katmanında uygulanır. Yeni bindMountOptions ise runtime tarafından konteyner içinde uygulanan bind mount bayraklarını kontrol eder. Farklı katmanlarda çalışırlar ve çakışmazlar.
  • fsGroup etkileşimi: Pod’un security context’inde fsGroup ayarlıysa, fsGroup ile uygulanan grup izinleri emptyDir için belirtilen mode değerini geçersiz kılar. Secret ve ConfigMap hacimlerindeki defaultMode için zaten var olan davranışın aynısı.
  • Yalnızca Linux: noexec, nosuid, nodev bayrakları ve Unix izin modları Linux kavramları. bindMountOptions Windows node’larda etkisiz; Windows Unix tarzı dosya izinlerini desteklemediği için emptyDir hacimlerinde mode alanı da atlanır.
  • Sürüm farkı güvenliği: Her iki özellik de eklemeli (additive). emptyDir mode için: API server’da kapı açık, kubelet’te kapalıysa alan kabul edilir ama yok sayılır ve kubelet 0777 davranışına döner. bindMountOptions için: scheduler, Node Declared Features ile Pod’ların runtime desteği olmayan node’lara yerleştirilmesini önler; Pod yine de böyle bir node’a düşerse kubelet seçenekleri sessizce yok saymak yerine Pod’u reddeder.

Katkı ve takip

Bu geliştirmeleri SIG Node ve SIG Storage yürütüyor. Ayrıntılar için KEP-5855 (bind mount seçenekleri) ve KEP-5502 (emptyDir izin modu) belgelerine bakabilirsiniz. Her iki SIG’e de Slack kanalları ve e-posta listeleri üzerinden ulaşmak mümkün.

Kaynaklar ve İleri Okuma

Bu yazı yapay zeka (büyük dil modelleri) ile hazırlanmış, insan editör tarafından incelenmiştir. İçerik üretim sürecimiz.
Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için YouTube ve GitHub hesaplarımı takip edin.

Haftalık Bülten

Her pazar özenle seçilmiş teknoloji yazıları doğrudan e-postanıza gelsin.

4 Yorum

  1. Sonunda emptyDir’e noexec verebilmek için initContainer’la takla atmaya gerek kalmayacak yani, güzel haber. Alpha’da olduğu için prod’da denemek biraz riskli ama feature gate açıp test ortamında bir bakacağım. GA’ya kaç sürüm sonra gelir sizce?

  2. emptyDir’e noexec bayrağını manifest’ten verebilmek uzun süredir eksikti, şimdiye kadar hep initContainer ile uğraşıp duruyorduk. Alpha’da olması biraz temkinli yaklaşmayı gerektiriyor ama security ekibimiz bunu duyunca sevinecek. Beta’ya ne zaman geçer sizce?

  3. Sonunda emptyDir’e noexec verebiliyoruz, bunu yıllardır securityContext’le dolaylı yollardan çözmeye çalışıyorduk. Alpha aşamasında olması biraz düşündürüyor ama prod’a gelmesi çok uzun sürmez umarım. Feature gate açıp test cluster’da denemeyi düşünüyorum.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

✉

Haftalık Bülten

Azure, DevOps ve Yapay Zeka dünyasındaki en güncel içerikleri her hafta doğrudan e-postanıza alın.

Spam yok. İstediğiniz zaman iptal edebilirsiniz.
📱
Uygulamayı Yükle Ana ekrana ekle, çevrimdışı oku
Kategoriler
Ara
Paylaş
WhatsApp
İçindekiler
← MCP ile Dağıtık Agent Skills: ...
Azure Local ve Azure Arc ile D... →
📩

Gitmeden önce!

Her pazar özenle seçilmiş teknoloji yazıları ve AI haberleri doğrudan e-postanıza gelsin. Ücretsiz, spam yok.

🔒 Bilgileriniz güvende. İstediğiniz zaman ayrılabilirsiniz.

📬 Haftalık bülten: Teknoloji + AI haberleri
Beni Takip Et Yeni Azure / AI / DevOps yazılarını GitHub ve RSS üzerinden takip edin.