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

container-security

Kafesin Parmaklıklarını Gevşetmek: Docker Escape ve Savunma Sanatı

Konteyner dünyasında güvenliğin sadece imaj taramaktan ibaret olmadığını, yanlış yapılandırılmış bir parametrenin nasıl tüm host sistemini ele geçirebileceğini teknik detaylarla inceliyoruz.

Sedat Özdemir
· 4 dk okuma

Saat sabahın 03:22'siydi. Terminaldeki imleç, sanki benimle dalga geçer gibi yanıp sönüyordu. testCompany'nin yeni devreye aldığı Kubernetes cluster'ında rutin bir sızma testi gerçekleştirirken, sıradan bir uygulama konteyneri içerisinde shell almıştım. Ancak asıl mesele shell almak değil, o daracık kafesten çıkıp host makinenin kontrolünü ele geçirmekti. /proc/self/status çıktısına baktığımda gördüğüm o tek bir satır, gecenin geri kalanının çok ilginç geçeceğini müjdeliyordu: CapEff: 0000003fffffffff. Yani karşımda, 'privileged' flag'i ile ayağa kaldırılmış, gardiyanı uyuyan bir hücre vardı.

Çoğu zaman konteynerleri 'hafif siklet sanal makineler' gibi düşünme hatasına düşüyoruz. Oysa konteynerler sadece birer izole process'ten ibaret. Bu izolasyonu sağlayan namespaces ve cgroups gibi Linux çekirdek özelliklerinin arasına ufacık bir çatlak sızdığında, o koca yapı bir iskambil kağıdı gibi yıkılabiliyor.

O Ölümcül Hata: Privileged Konteynerler

Yazılımcı arkadaşların bazen işleri hızlıca çözmek için başvurduğu --privileged parametresi, aslında güvenliğe sıkılmış bir kurşundur. Bu parametre, konteyner içindeki root kullanıcısına host üzerindeki neredeyse tüm kernel yetkilerini verir.

Bir Red Teamer olarak böyle bir konteynere sızdığımda ilk yaptığım şey, hostun diskini kendi üzerime mount etmektir. Mantık basit: Eğer ben hostun tüm aygıtlarına erişebiliyorsam, neden hostun ana diskini görmeyeyim?

# Zararsızlaştırılmış Escape Senaryosu
# Adım 1: Mevcut diskleri listele
fdisk -l

# Adım 2: Hostun ana diskini (örneğin /dev/sda1) konteyner içinde bir klasöre bağla
mkdir /mnt/host_root
mount /dev/sda1 /mnt/host_root

# Adım 3: Artık hostun /etc/shadow dosyasına erişebilirim
cat /mnt/host_root/etc/shadow

Bu noktadan sonra sistem yöneticisinin şifre karmasını (hash) alıp kırmak ya da kendi SSH anahtarımı /mnt/host_root/root/.ssh/authorized_keys içine yazmak sadece saniyelerimi alır.

Savunma Notu: Asla, ama asla konteynerleri privileged: true ile çalıştırmayın. Eğer spesifik bir donanıma erişim gerekiyorsa, sadece ilgili capability birimlerini (--cap-add) ekleyin.

Docker Socket: Krallığın Anahtarını Paspasın Altına Koymak

Bir diğer klasik ama hala yaygın hata ise /var/run/docker.sock dosyasının konteyner içine mount edilmesidir. Genellikle CI/CD tool'ları veya izleme araçları 'Docker içinde Docker' (DinD) çalıştırmak için buna ihtiyaç duyar. Ancak bu dosya, Docker daemon ile konuşan API'nin ta kendisidir. Bu sokete erişimi olan bir saldırgan, Docker daemon'a 'bana hostun root dizinini mount eden yeni bir konteyner yarat' komutunu verebilir.

# Docker socket erişimi olan bir saldırganın yapacağı hamle
docker run -it -v /:/host_root alpine:latest chroot /host_root

Bu komut çalıştığı an, saldırgan artık konteynerde değil, host makinenin ta kendisindedir.

İmaj Güvenliği: 'Latest' Kumarı

Sadece runtime değil, build aşaması da bir o kadar kritik. Dockerfile yazarken FROM python:latest dediğinizde, o imajın içinde ne olduğunu tam olarak bilmiyorsunuz demektir. Belki de upstream'deki bir kütüphane zehirlendi (supply chain attack).

Kendi ortamlarımızda her zaman imajları hash değeriyle (SHA256) sabitlemeyi ve 'Distroless' imajlar kullanmayı öneriyoruz. İçinde shell, curl, apt olmayan bir imajda, saldırgan sızsa bile hareket alanı kısıtlıdır. Bakınız kötü bir örnek:

# TEHLİKELİ: Gereksiz paketler ve root kullanımı
FROM ubuntu:latest
RUN apt-get update && apt-get install -y netcat curl python3
COPY . /app
WORKDIR /app
CMD ["python3", "server.py"]

Şimdi bunu nasıl 'hardened' hale getireceğimize bakalım:

# GÜVENLİ: Spesifik imaj, root olmayan kullanıcı, minimum paket
FROM python:3.11-slim@sha256:12345abcde... 
RUN groupadd -r myuser && useradd -r -g myuser myuser
USER myuser
WORKDIR /home/myuser/app
COPY --chown=myuser:myuser . .
# Gereksiz tüm binary'lerden arındırılmış bir ortam
CMD ["python", "app.py"]

Runtime Koruması: Seccomp ve AppArmor

Bir Red Teamer olarak en sevmediğim şey, bir exploit çalıştırmaya çalışırken Operation not permitted hatası almaktır. Bu genellikle sistemin Seccomp (Secure Computing Mode) veya AppArmor/SELinux ile korunduğunu gösterir.

Docker varsayılan olarak yaklaşık 300 syscall'dan 40 küsurunu engeller. Ancak bu yeterli mi? Çoğu zaman hayır. Kritik bir uygulamayı ayağa kaldırırken, uygulamanın sadece ihtiyaç duyduğu syscall'lara izin veren bir profil oluşturmak, saldırganın exploit payload'unu daha kernel seviyesindeyken boğar.

Saha Tecrübesi: 'Immutable' Altyapı

Geçen sene yaşadığımız bir vakada, saldırgan bir RCE (Remote Code Execution) açığı üzerinden konteynere sızmıştı. Ancak konteyner read-only root filesystem ile çalıştığı için ne bir script indirebildi, ne de /tmp dışında bir yere dosya yazabildi. Sisteme kalıcılık (persistence) sağlayamadığı için de ilk restart'ta uçup gitti.

Konteynerlerinizi --read-only flag'i ile çalıştırmak, güvenliği bir üst seviyeye taşır. Yazılması gereken spesifik yerler varsa oralara sadece kısıtlı tmpfs mount'ları verin.

Ne Yapmalı? (Protokol Listesi)

  1. Root Kullanıcısını Terk Edin: Docker imajlarınızın içinde asla root olmayın. USER 1001 gibi bir tanım hayat kurtarır.
  2. Secret Yönetimi: Şifreleri, API key'leri asla Environment Variable (ENV) olarak vermeyin. /proc/self/environ üzerinden bunları okumak çok kolay. Kubernetes Secret veya HashiCorp Vault gibi çözümlere yönelin.
  3. Network İzolasyonu: Konteynerler arası iletişimi 'default allow' bırakmayın. Network Policy'ler ile sadece gerekli servislerin birbiriyle konuşmasını sağlayın.
  4. İmaj Taraması: CI hattına mutlaka trivy veya grype gibi araçlar entegre edin.

Konteyner güvenliği bir varış noktası değil, bir yolculuk. 'Benim konteynerim zaten izole' diyerek arkaya yaslanmak, fırtınalı denizde can yeleği giymeden oturmaya benzer. Unutmayın, saldırganların sadece bir kez haklı çıkması yeterli, sizinse her zaman.

İlgili yazılar