Kubernetes v1.37: emptyDir ve Bind Mount Sertleştirmesi
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‘ınnoexecile 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 (
emptyDirya da/tmpmount’ları)nosuidvenoexecile 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üzerindemode: 01777ayarlandığında alan klasik Unix/tmpgibi 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‘amode: 0750verilerek 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:
bindMountOptionsbelirtmez ya daemptyDiriçinmodeayarlamazsanız eskisiyle birebir aynı varsayılan davranışı (örneğin0777izinleri) 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.modealanı ise tümemptyDirmedium türlerinde geçerli: varsayılan (disk tabanlı),Memory(tmpfs) veHugePages. - Runtime yetenekleri önemli (yalnızca
bindMountOptionsiçin): Container runtime’ın CRImount_optionsalanını desteklemesi ve bunuruntimeFeaturesü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.emptyDiriçinmodekullanmaksa runtime desteği gerektirmez. - PV mountOptions ile aynı şey değil: PersistentVolume
mountOptionsalanı, CSI sürücüsü aracılığıyla depolama katmanında uygulanır. YenibindMountOptionsise 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
fsGroupayarlıysa,fsGroupile uygulanan grup izinleriemptyDiriçin belirtilenmodedeğerini geçersiz kılar. Secret ve ConfigMap hacimlerindekidefaultModeiçin zaten var olan davranışın aynısı. - Yalnızca Linux:
noexec,nosuid,nodevbayrakları ve Unix izin modları Linux kavramları.bindMountOptionsWindows node’larda etkisiz; Windows Unix tarzı dosya izinlerini desteklemediği içinemptyDirhacimlerindemodealanı da atlanır. - Sürüm farkı güvenliği: Her iki özellik de eklemeli (additive).
emptyDirmodeiçin: API server’da kapı açık, kubelet’te kapalıysa alan kabul edilir ama yok sayılır ve kubelet0777davranışına döner.bindMountOptionsiç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
- Kubernetes Blog: Hardening Container Storage with Bind Mount Options and EmptyDir Permissions
- Kubernetes Dokümantasyonu: Configure Bind Mount Options
- Kubernetes Dokümantasyonu: Configure emptyDir Volume Mode
- Kubernetes Dokümantasyonu: Volumes
- Issue #48912: emptyDir üzerinde mount seçenekleri
- Issue #119627: 1.24 güvenlik denetimi bulgusu NCC-E003660-7HM
- KEP-5855: Bind mount options
- KEP-5502: emptyDir permission mode
- SIG Node topluluk sayfası
- SIG Storage topluluk sayfası
- SIG Storage’ı Tanımak: Kubernetes’te Veri Kalıcılığının Mutfağı
- Kubernetes 1.36 Ön İzleme: Neler Geliyor, Neler Gidiyor?







Yorum gönder