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

cloud-security

Konteyner Dünyasında 'Root' Olma Yanılgısı: Kendi Kalene Gol Atmamak

Konteynerler seni izole etmez, sadece öyle hissettirir. Docker dünyasında yapılan en kritik hataları ve pratik çözüm yollarını konuştuk.

Sedat Özdemir
· 4 dk okuma

"Konteyner kullanıyoruz abi, her şey izole, dışarıyla bağlantısı yok" diyen birini gördüğümde genelde hafifçe gülümsüyorum. İşin aslı şu ki; o içine girdiğin ve kendini güvende hissettiğin "box", doğru konfigüre edilmediyse aslında sadece mukavvadan bir kutu. Üstelik bu kutunun anahtarlarını da çoğu zaman kapının üzerinde bırakıyorsun.

Geçenlerde bir sızma testinde denk geldim; adamlar muazzam bir mikroservis mimarisi kurmuşlar, Kubernetes falan havada uçuşuyor. Ama içeri bir girdik, baktık ki neredeyse tüm konteynerler root kullanıcısıyla çalışıyor. Daha kötüsü, Docker socket'i olduğu gibi konteynerin içine mount edilmiş. Yani aslında kapıyı kilitlemişler ama anahtarı paspasın altına bile değil, direkt kilidin üstünde bırakmışlar.

Root Olmak Neden Başına Bela Olur?

Çoğu developer arkadaşım Dockerfile yazarken USER komutunu kullanmayı unutuyor ya da "Aman şimdi izinlerle uğraşmayayım, çalışsın yeter" diyerek geçiştiriyor. Ama bak, senin o konteynerin içinde root olman, host makinede de root olma yolunda atılmış dev bir adım.

Eğer bir saldırgan uygulamanın içinde bir açık bulursa (ki bulur, kaçış yok), direkt root yetkisiyle içeri giriyor. Oradan sonrası artık onun hayal gücüne kalmış.

Bunun yerine Dockerfile'ına şunu eklemek topu topu 5 saniyeni alır:

# Kötü örnek: Default olarak root çalışır
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "index.js"]

# İyi örnek: Kendi kullanıcını yarat
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
RUN npm install
CMD ["node", "index.js"]

İşin aslı, production ortamında çalışan bir konteynerin neden root yetkisine ihtiyacı olsun ki? Sadece dosyaları okuyup web isteğine cevap verecekse, appuser fazlasıyla yeterli.

Docker Socket: En Büyük Zafiyetin Olabilir

Bak bu konu çok kritik. /var/run/docker.sock dosyasını bir konteynerin içine mount ettiğin an, o konteynere "Sen bu makinenin sahibisin" demiş oluyorsun. Saldırgan bu socket'e eriştiği an, host makine üzerinde yeni konteynerler başlatabilir, mevcut olanları durdurabilir hatta host makinenin dosya sistemine erişebilir.

Bir pentest sırasında şöyle bir şey yapmıştık: Bir monitoring aracının Docker socket'ine erişimi vardı. O socket üzerinden host makinedeki tüm diskleri /mnt altına mount eden yeni bir "privileged" konteyner ayağa kaldırdık. Sonuç? Host makinenin /etc/shadow dosyası elimizdeydi. Tüm sistemin şifreleri...

Eğer gerçekten Docker socket'ine ihtiyacın yoksa (ki %99 yoktur), sakın ha sakın onu volumes altına ekleme. Eğer CI/CD süreçleri için lazımsa, Docker-in-Docker (DinD) yerine daha güvenli alternatiflere (örneğin Kaniko) bakmanı öneririm.

"Privileged" Konteyner: Açık Çek Vermek

Bazen karşıma çıkıyor, adam docker run --privileged ... diye bir komut çalıştırıyor. Neden diyorum, "Eee, anca böyle çalıştı, permission hatası alıyordum" diyor. Bu, sinek öldürmek için eve bazukayla dalmaya benziyor.

--privileged bayrağı, konteynere host makinenin tüm kernel yeteneklerini (capabilities) verir. Yani konteynerin içinden çıkıp host makinenin donanımına müdahale etmek çocuk oyuncağı olur.

Onun yerine, sadece ihtiyacın olan yetkiyi vermelisin. Mesela sadece ağ ayarlarıyla ilgili bir işin varsa:

# Hatalı ve tehlikeli
docker run --privileged my-image

# Daha mantıklı: Sadece gerekeni ver
docker run --cap-add=NET_ADMIN my-image

Hatta bence en güzeli, önce her şeyi bir yasakla (--cap-drop=ALL), sonra hata aldıkça "Acaba buna gerçekten ihtiyacım var mı?" diyerek tek tek ekle. Güvenlik böyle bir şey; önce kapıları kapatırsın, sonra lazım olanları aralarsın.

Image Seçerken Dikkat Et: Kimin Bu Görüntü?

Docker Hub'a giriyorsun, "alpine-node-python-mysql" diye bir image aratıyorsun. Bir bakıyorsun, 2 yıl önce yüklenmiş, 500 star almış bir image var. "Hah, tam istediğim şey" deyip docker pull yapıyorsun. Yapma.

O image'ın içinde ne var biliyor musun? Belki içinde bir reverse shell bekliyor, belki de kripto madenci (miner) gömülü. Kendi deneyimlerimden biliyorum, bir image'ı base alırken her zaman resmi (official) olanları veya güvenilirliği kanıtlanmış (verified) yayıncıları seçmelisin.

Hatta daha iyisi, image'larını düzenli olarak tara. Trivy gibi araçlar var, kullanımı da inanılmaz basit:

trivy image my-app-image:latest

Bunu CI hattına koyduğunda, içinde kritik bir zafiyet (CVE) olan image'ın production'a çıkmasını engellersin. Gece 3'te telefonun çalmasından iyidir, inan bana.

Dosya Sistemini Salt-Okunur Yapmak

Bir saldırgan içeri girdiğinde ilk yapacağı şey nedir? Kendi tool'larını indirmek, script'lerini çalıştırmak. Eğer konteynerinin dosya sistemini read-only yaparsan, saldırganın elini kolunu bağlarsın.

docker run --read-only ... dediğinde, konteyner içine hiçbir şey yazılamaz hale gelir. "Ama log yazmam lazım, temp dosyalarım var" diyorsan, sadece o spesifik klasörleri tmpfs olarak mount edebilirsin:

docker run --read-only --tmpfs /tmp --tmpfs /var/log my-image

Bu basit hamle, birçok otomatik saldırı script'ini daha başlamadan bitirir.

Son Olarak Bir Tavsiye

Konteyner güvenliği bir varış noktası değil, bir süreç. Bugün güvenli dediğin image, yarın çıkan bir zafiyetle (mesela Log4j faciası gibi) bir anda savunmasız kalabilir.

Senin yapman gereken; en az yetki prensibiyle hareket etmek (Least Privilege), image'larını güncel tutmak ve mutlaka ama mutlaka otomatize edilmiş tarama araçlarını kullanmak.

Bence bu işin sırrı "Ben bunu nasıl kırarım?" diye düşünmekte. Kendi sistemine bir saldırgan gözüyle baktığında, o açık bıraktığın kapıları çok daha net görüyorsun. Dikkat etmen gereken en önemli şey, güvenliği bir engel değil, sistemin bir parçası olarak görmek.

Kafana takılan bir şey olursa veya "Şu senaryoda ne yapardın?" dersen, her zaman buradayım. Konteynerler güzeldir ama dizginleri elden bırakmamak şartıyla.

İlgili yazılar