DOCKER SECURITY VE IMAGE SCAN

Docker mavi balina logosu üzerinde küçük bir kalkan rozeti ile container güvenlik taraması metaforu

Docker Hub'daki popüler public image'ler üzerinde düzenli yapılan taramalar, bunların önemli bir kısmının yayımlandıkları gün bile yüksek veya kritik seviyede bilinen güvenlik açıkları içerdiğini ortaya koyuyor. Bir Node.js veya Python uygulamasını "official" bir image'in üstüne kurup production'a iten ekip, farkında olmadan onlarca CVE'yi de paketin içine taşımış olur. Image scan bu yüzden bugün container yaşam döngüsünde test ve build kadar temel bir adım sayılıyor. Bu yazı geliştirici, DevOps mühendisi veya sistem yöneticisi olarak Docker ile production çalıştıran herkesin image güvenlik taramasını net bir zihin haritasıyla kavraması için yazıldı.

Image Scan Neyi, Nasıl Tarar?

Image scan basitçe şu sorunun cevabıdır: "Bu image'ın içindeki paketlerin hangileri bilinen güvenlik açıklarına sahip?" Scanner image'i bir tarball olarak açar, içindeki dosya sistemini gezer ve birkaç farklı kaynaktan paket envanteri çıkarır:

  • OS paket yöneticisi metadata'sı (/var/lib/dpkg/status, /var/lib/rpm, /lib/apk/db/installed)
  • Dil ekosistemine özgü manifest dosyaları (package-lock.json, requirements.txt, go.sum, pom.xml)
  • Binary'lerden çıkarılan versiyon imzaları — Go ile static derlenmiş binary'lerin içine gömülü modül listesi gibi

Bu envanter sonra public CVE veritabanlarıyla karşılaştırılır. Ana referans ulusal açık güvenlik veritabanı ve onun üzerine kurulu dağıtım-spesifik feed'lerdir: Debian Security Tracker, Alpine secdb, Red Hat OVAL, GitHub Advisory Database. Her bulgu CVE numarası, etkilenen versiyon aralığı, fix versiyonu ve CVSS puanı ile raporlanır. Yani scan aslında fingerprint + lookup operasyonudur — yeni bir saldırı keşfeder gibi davranmaz, sadece zaten bilinen açıkların image'da bulunup bulunmadığına bakar.

Base Image Seçimi Yüzey Alanını Belirler

Bir scan raporunun çıktısı büyük ölçüde base image seçimi tarafından belirlenir. ubuntu:22.04 üstüne kurulan bir Node.js uygulaması; uygulamanın hiç dokunmadığı yüzlerce pakete (curl, gcc, perl, openssl tooling, locales) maruz kalır. Aynı uygulama node:20-alpine üstüne kurulduğunda paket sayısı bir büyüklük mertebesi düşer; gcr.io/distroless/nodejs üstüne kurulduğunda neredeyse sadece runtime kalır — shell bile yoktur.

Genel pratik kalıp:

  • Production final: distroless veya minimal alpine — paket sayısı az, scan raporu temiz
  • Build aşaması: tam dağıtım image'i (debian, ubuntu) — derleme araçlarına ihtiyaç var
  • Final image: multi-stage build ile yalnızca çalışma için gerekli binary'ler kopyalanır

Multi-stage yaklaşımı, scan'in çıktısını birkaç saatte 200 critical CVE'den 0-3 critical'a indirebilir. Yüzey alanı küçüldükçe taranacak yüzey ve patch yükü beraber azalır. Distroless image'ın bir başka pratik etkisi de saldırgan içeri girse bile elinde shell, curl, paket yöneticisi olmadığı için pivot yapmasının zorlaşmasıdır.

Ubuntu, Alpine ve Distroless base image katmanlarının paket sayısı ve CVE yükü açısından üç sütunlu karşılaştırma diyagramı

Açık Kaynak Scanner Araçları

Image taraması için yaygın kullanılan birkaç araç var ve hemen hepsi açık kaynak olarak ücretsiz çalışır. Aralarındaki farklar daha çok ekosistem entegrasyonu ve çıktı formatından kaynaklanır:

Trivy (Aqua Security)
En yaygın açık kaynak scanner. OS paketleri, dil bağımlılıkları, Terraform/Kubernetes manifest'leri ve secret'ları tek komutla tarar. Hızlı, CI-dostu çıktı verir.
Grype (Anchore)
SBOM-temelli yaklaşımıyla dikkat çeker. Önce Syft ile SBOM çıkarır, sonra Grype onu tarar; CI'da artifact olarak SBOM saklamak isteyen ekipler bu ayrımı sever.
Docker Scout
Docker'ın resmi entegre çözümü. Docker Desktop ve Docker Hub'a doğrudan bağlı; en yakın "tek komutla bütünleşik scan" deneyimi sunar. Resmi belgelendirmeyi Docker dokümantasyonunda bulabilirsiniz.
Clair
Quay/Red Hat tarafından geliştirilen, registry tarafı tarama için tasarlanmış servis modeli scanner. Self-hosted registry'lerde popüler.

Pratikte hızlı başlamak isteyenler için Trivy en düşük sürtünmeli seçenektir:

  • trivy image node:20 — bir komut, anında rapor
  • --severity HIGH,CRITICAL — sadece yüksek seviyeleri göster
  • --exit-code 1 --severity CRITICAL — CI'da critical bulgu varsa pipeline'ı kır
  • --ignore-unfixed — fix'i olmayan açıkları rapor dışı bırak (gürültü azaltır)

CI/CD'ye Entegrasyon ve Tag Disiplini

Image scan'in gerçek değeri manuel çalıştırmadan değil, build pipeline'ına gömülü olmasından gelir. Tipik bir akış şöyledir:

  1. Image build edilir
  2. Build edilen image scan'lenir (Trivy, Scout veya tercih edilen başka bir araç)
  3. Severity policy'ye göre exit 1 verilir ya da geçilir
  4. Yalnızca policy'yi geçen image registry'ye push edilir
  5. Production deploy yalnızca taranmış-onaylanmış digest'lerden yapılır

Bu zincirde kritik nokta tag immutability'dir: bir image bir kez tag'lenip push edildikten sonra üzerine farklı bir içerikle aynı tag yazılmamalı. Aksi halde v1.2.3 tag'i bugün temiz, yarın açıklı olabilir ve siz farkına varmadan production'da iki farklı içerik bulundurursunuz. Çözüm: :latest kullanımını yasaklamak, SHA digest pinning (image@sha256:abc...) veya semantic version ile birlikte registry tarafında immutable repo policy kullanmak.

Docker'la production ortamında çalışıyorsanız bu konuların pratiğini bütünsel görmek için Docker eğitimi imaj yapısından registry mimarisine kadar uygulamalı oturumlar içerir.

Build, scan, policy ve push aşamalarından oluşan CI pipeline akışı yanında critical, high, medium, low severity merdiveni

SBOM ve Severity Politikası

SBOM (Software Bill of Materials), bir image'ın içindeki tüm paketlerin makine okunabilir listesidir. Tedarik zinciri saldırılarına karşı son birkaç yılda fiili standart haline geldi; ABD'de federal yazılım alımları artık SBOM zorunluluğu içeriyor. Syft veya Trivy ile JSON, SPDX ya da CycloneDX formatında üretilir; image ile birlikte registry'de saklanır (cosign attestation). Bunun pratik faydası şu: bir CVE bugün yayımlandığında, hangi image'lardan etkilendiğinizi yeniden tarama yapmadan SBOM üzerinde sorgulayabilirsiniz.

Severity politikası ise her ekibin kendi bağlamına göre kalibre ettiği bir eşiktir. Yaygın bir kademe örneği:

  • Critical: Build kırılır, push engellenir
  • High: Build geçer, ticket otomatik açılır, sprint içinde patch'lenir
  • Medium: Aylık review
  • Low / Negligible: Yıllık audit, çoğunlukla kabul edilir

Mutlak "sıfır CVE" hedefi pratikte çoğu zaman gerçekçi değildir — özellikle base OS bağımlılıkları için. Hedef, yamalanabilir olanı zamanında yamalamak; istisnaları gerekçeleriyle birlikte belgelemek olmalıdır. Belirsizlik bırakan tek satırlık "kabul edildi" notları, denetim sırasında en zayıf halkadır.

Pratik Önlemler ve Sık Hatalar

Image güvenliği tek başına scan ile bitmez; scanner'ın doğru raporlayacağı bir tasarımı sağlamak da onun kadar önemlidir:

  • Versiyonu sabitle: FROM node:20 yerine FROM node:20.11.1-alpine3.19. Latest tag'i unutulması gereken bir tuzaktır.
  • Multi-stage kullan: Build araçları final image'a sızmamalı. Derleme aşaması ayrı, runtime aşaması ayrı olmalı.
  • Root kullanma: USER node ile non-root kullanıcıya düş. Container içinde root, host'ta tam kullanıcı olmasa da pod escape senaryolarında saldırı yüzeyini büyütür.
  • Secret commit etme: Layer'lar değişmezdir. Bir layer'a yazılan secret silinemez, sadece üstüne ekleme yapılır. --secret mount veya buildkit secret disiplini gerekir.
  • Düzenli yeniden build: Otuz gün önce build ettiğiniz image bugün açıklı olabilir; CI'da haftalık yeniden build cron'u kurulmalı.
  • Registry tarafında rescan: Push anındaki tarama bir an'lık fotoğraftır; registry üzerinde periyodik rescan ve yeni CVE alarmı gerekir.

Son nokta sık atlanır: bir image scan'i bir an'lık fotoğraftır. Bugün temiz raporlanan image yarın yeni bir CVE yayımlandığında açıklı hale gelebilir. Bu yüzden registry tarafında periyodik rescan, runtime tarafında ise Kubernetes için OPA Gatekeeper veya Kyverno ile admission policy birlikte kurulduğunda scan gerçekten koruyucu bir katmana dönüşür. Tek başına bir CI adımı olarak görüldüğünde, taranmamış hot-fix image'lerinin manuel deploy'larıyla kolayca atlanabilen bir yumuşak engele dönüşür.