Container Güvenliği: Docker ve Kubernetes Hardening
Container Güvenliğine Giriş
Container teknolojileri, modern yazılım geliştirme süreçlerinin vazgeçilmez bir parçası haline gelmiştir. Ancak containerların yaygınlaşmasıyla birlikte güvenlik tehditleri de önemli ölçüde artmıştır. Docker ve Kubernetes ortamlarında güvenlik açıkları, tüm altyapınızı tehlikeye atabilir. Bu yazıda, container güvenliğini sağlamak için uygulamanız gereken hardening tekniklerini detaylı şekilde inceleyeceğiz.
Docker Hardening
1. Minimal Base Image Kullanımı
Container imajlarınız ne kadar küçükse, saldırı yüzeyi o kadar dar olur. ubuntu veya debian gibi tam teşekküllü imajlar yerine, Alpine Linux veya distroless imajları tercih edin.
# Kötü Uygulama
FROM ubuntu:latest
# İyi Uygulama
FROM alpine:3.19
# En İyi Uygulama
FROM gcr.io/distroless/static-debian12
Distroless imajlar, shell bile içermediği için bir saldırgan container içine sızsa dahi hareket alanı son derece kısıtlı olacaktır.
2. Root Olmayan Kullanıcı ile Çalıştırma
Containerları root kullanıcısıyla çalıştırmak, en yaygın güvenlik hatalarından biridir. Dockerfile içinde mutlaka ayrı bir kullanıcı tanımlayın:
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]
3. Read-Only Dosya Sistemi
Containerların dosya sistemini salt okunur modda çalıştırmak, zararlı yazılım enjeksiyonunu büyük ölçüde engeller:
docker run --read-only --tmpfs /tmp --tmpfs /var/run myapp:latest
4. Capability Kısıtlamaları
Linux kernel capability'leri varsayılan olarak geniş yetkiler tanır. Tüm capability'leri kaldırıp yalnızca gerekli olanları ekleyin:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp:latest
Bu yaklaşımla container yalnızca ağ portlarına bağlanma yetkisine sahip olur; dosya sistemi, süreç yönetimi ve diğer kritik kernel işlevlerine erişimi engellenir.
5. Docker Content Trust ve İmaj Tarama
İmaj bütünlüğünü doğrulamak için Docker Content Trust özelliğini aktif edin ve düzenli olarak güvenlik taraması yapın:
# Content Trust Aktifleştirme
export DOCKER_CONTENT_TRUST=1
# Trivy ile imaj tarama
trivy image --severity HIGH,CRITICAL myapp:latest
# Grype ile alternatif tarama
grype myapp:latest
6. Multi-Stage Build ile Sırları Koruma
Build aşamasında kullanılan araçlar, anahtarlar veya bağımlılıklar final imaja taşınmamalıdır:
# Build aşaması
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o /app
# Final aşama - yalnızca binary
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
Kubernetes Hardening
1. Pod Security Standards (PSS)
Kubernetes 1.25 ile birlikte PodSecurityPolicy kaldırılmış, yerine Pod Security Standards getirilmiştir. Namespace düzeyinde güvenlik politikaları uygulayın:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
restricted profili; root olarak çalışmayı, privilege escalation'ı, hostNetwork ve hostPID kullanımını engeller.
2. SecurityContext Yapılandırması
Her Pod ve container tanımında detaylı güvenlik bağlamı belirleyin:
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
template:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:v1.2.3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
resources bloğu da güvenlik açısından kritiktir; kaynak limitleri tanımlanmamış bir container, tüm node kaynaklarını tüketerek DoS durumuna yol açabilir.
3. Network Policy ile Mikro Segmentasyon
Varsayılan olarak Kubernetes'te tüm Pod'lar birbirleriyle iletişim kurabilir. NetworkPolicy ile yalnızca gerekli trafiğe izin verin:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Önce tüm trafiği engelleyip (deny-all), ardından yalnızca gerekli iletişim yollarını açmak en güvenli yaklaşımdır.
4. RBAC Yapılandırması
Kubernetes RBAC (Role-Based Access Control) yapılandırmasında en az yetki ilkesini uygulayın:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: app-reader
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: ServiceAccount
name: app-sa
namespace: production
roleRef:
kind: Role
name: app-reader
apiGroup: rbac.authorization.k8s.io
ClusterRole yerine namespace bazlı Role kullanmayı tercih edin. Wildcard (*) kullanımından kesinlikle kaçının.
5. Secret Yönetimi
Kubernetes Secret'ları varsayılan olarak yalnızca base64 ile kodlanır, şifrelenmez. Ek önlemler alın:
- EncryptionConfiguration ile etcd üzerinde rest-at-encryption aktif edin
- Sealed Secrets, HashiCorp Vault veya External Secrets Operator gibi araçlar kullanın
- Secret'ları environment variable yerine volume mount olarak bağlayın
- Secret'ları Git deposuna kesinlikle commit etmeyin
# etcd şifreleme yapılandırması
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret:
- identity: {}
6. Audit Logging
Kubernetes API sunucusunda denetim günlüklerini aktif ederek tüm erişimleri kaydedin:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: RequestResponse
resources:
- group: ""
resources: ["pods"]
verbs: ["create", "delete"]
Sürekli Güvenlik Kontrolleri
Container güvenliği tek seferlik bir işlem değil, sürekli bir süreçtir. Aşağıdaki araç ve pratikleri CI/CD pipeline'ınıza entegre edin:
- Trivy / Grype: İmaj güvenlik açığı taraması
- OPA Gatekeeper / Kyverno: Kubernetes admission kontrolü ile politika uygulaması
- Falco: Çalışma zamanı tehdit algılama
- kubeaudit / kube-bench: CIS benchmark kontrolü
- Cosign: İmaj imzalama ve doğrulama
# CI/CD pipeline örneği (GitHub Actions)
- name: Build Image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan Image
run: trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:${{ github.sha }}
- name: Sign Image
run: cosign sign --key cosign.key myapp:${{ github.sha }}
Özet ve En İyi Uygulamalar Kontrol Listesi
- Minimal ve distroless base imajlar kullanın
- Containerları asla root olarak çalıştırmayın
- Dosya sistemini salt okunur yapın
- Tüm Linux capability'lerini kaldırıp yalnızca gereklileri ekleyin
- Pod Security Standards ile
restrictedprofil uygulayın - NetworkPolicy ile varsayılan olarak tüm trafiği engelleyin
- RBAC'ta en az yetki ilkesini benimseyin
- Secret'ları şifreleyin ve harici yönetim araçları kullanın
- İmajları düzenli olarak tarayın ve imzalayın
- Çalışma zamanı güvenliğini Falco gibi araçlarla izleyin
Container güvenliği, derinlemesine savunma (defense in depth) prensibine dayanır. Tek bir güvenlik katmanına güvenmek yerine, her seviyede koruma sağlayarak saldırı yüzeyini minimize edin. Güvenlik yapılandırmalarınızı düzenli olarak gözden geçirin ve güncel tehditlere karşı sürekli adapte olun.