Container Security: Kubernetes'te Güvenli Container İmajları ile Çalışma
Container teknolojilerinin yaygınlaşmasıyla birlikte, container security modern DevOps ve platform mühendisliği ekiplerinin en kritik sorumluluklarından biri haline geldi. Tek bir güvenlik açığı, production cluster'ınızda ciddi veri sızıntılarına, yetkisiz erişimlere ve compliance ihlallerine yol açabilir.
Bu yazıda, container security'nin temellerinden başlayarak Trivy ile pratik vulnerability scanning, image hardening, supply chain security ve Kubernetes'te güvenli deployment stratejilerine kadar kapsamlı bir rehber sunuyoruz. Production ortamlarında kullanabileceğiniz pratik örnekler ve CI/CD entegrasyonları ile container güvenliğinizi sıfırdan kurabileceksiniz.
İçindekiler
- Container Security'ye Giriş
- Container Güvenlik Riskleri
- Trivy Nedir ve Neden Kullanmalıyız?
- Trivy Kurulumu ve İlk Tarama
- Image Vulnerability Scanning
- Filesystem ve IaC Scanning
- CI/CD Pipeline Entegrasyonu
- Kubernetes Cluster Scanning
- Container Image Hardening
- Multi-Stage Builds ve Minimal Base Images
- Supply Chain Security ve SBOM
- Kubernetes Security Context
- Runtime Security: Falco Integration
- Policy Enforcement: OPA ve Kyverno
- Production Best Practices
- Monitoring ve Alerting
Container Security'ye Giriş {#giris}
Container Güvenliği Neden Kritik?
Modern microservice mimarilerinde bir uygulama yüzlerce container içerebilir. Her bir container:
- Onlarca dependency içerir (npm packages, apt packages, Python libraries)
- Base image'dan miras alınan paketler vardır
- Sürekli güncellenen vulnerability veritabanları ile taranmalıdır
- Supply chain attacks riski taşır
Gerçek dünya örneği: 2021'de Log4Shell (CVE-2021-44228) açığı keşfedildiğinde, milyonlarca container bu kütüphaneyi içeriyordu. Vulnerability scanning yapan ekipler etkilenen sistemleri saatler içinde tespit edip güncelleyebildi; diğerleri haftalarca açık kaldı.
Container Security Katmanları
┌─────────────────────────────────────┐
│ Registry Security (Harbor, ECR) │ ← Image imzalama, erişim kontrolü
├─────────────────────────────────────┤
│ Image Scanning (Trivy, Grype) │ ← Vulnerability detection
├─────────────────────────────────────┤
│ Build-Time Security (CI/CD) │ ← Güvenli image build, SBOM
├─────────────────────────────────────┤
│ Deployment Security (K8s) │ ← Security contexts, policies
├─────────────────────────────────────┤
│ Runtime Security (Falco) │ ← Anomaly detection, monitoring
└─────────────────────────────────────┘
Bu yazıda image scanning ve build-time security odaklı çalışacağız.
Container Güvenlik Riskleri {#riskler}
Yaygın Vulnerability Türleri
1. Known CVEs (Common Vulnerabilities and Exposures)
# Örnek: Outdated base image
FROM ubuntu:18.04 # ⚠️ EOL, 200+ known vulnerabilities
RUN apt-get update && apt-get install -y openssl=1.1.0 # ⚠️ Critical CVE
2. Misconfigured Containers
# ❌ Kötü pratikler
FROM node:latest # Unstable, unpredictable
USER root # Root privilege
COPY . /app # Root ownership
3. Secrets in Images
# ❌ Asla yapmayın!
ENV DATABASE_PASSWORD="prod-password-123"
COPY .env /app/.env
RUN echo "API_KEY=sk-xxx" >> config.yaml
4. Supply Chain Attacks
- Malicious npm packages (event-stream incident)
- Compromised base images
- Typosquatting attacks
5. Excessive Privileges
# ❌ Tehlikeli Kubernetes deployment
securityContext:
privileged: true # Host'a tam erişim
runAsUser: 0 # Root kullanıcı
Trivy Nedir ve Neden Kullanmalıyız? {#trivy-nedir}
Trivy, Aqua Security tarafından geliştirilen açık kaynak bir vulnerability scanner. Neden popüler?
Trivy'nin Avantajları
✅ Comprehensive Coverage
- OS packages (Alpine, Debian, Ubuntu, RHEL, Amazon Linux...)
- Application dependencies (npm, pip, gem, cargo, go modules...)
- Infrastructure as Code (Terraform, CloudFormation, Kubernetes YAML)
- Config files (Dockerfile, docker-compose.yml)
✅ Hızlı ve Hafif
- Offline kullanım desteği (air-gapped environments)
- Vulnerability DB otomatik güncelleme
- Saniyeler içinde tam image tarama
✅ CI/CD Friendly
- Exit codes ile pipeline blocking
- JSON/SARIF output formatları
- GitHub Actions, GitLab CI, Jenkins entegrasyonu
✅ Kubernetes Native
- Cluster-wide scanning
- Operator support
- Admission controller integration
Alternatifler ve Karşılaştırma
| Tool | Coverage | Speed | K8s Support | Free |
|---|---|---|---|---|
| **Trivy** | ⭐⭐⭐⭐⭐ | ⚡⚡⚡ | ✅ | ✅ |
| Grype | ⭐⭐⭐⭐ | ⚡⚡⚡ | ⚠️ | ✅ |
| Snyk | ⭐⭐⭐⭐⭐ | ⚡⚡ | ✅ | Limited |
| Clair | ⭐⭐⭐ | ⚡⚡ | ✅ | ✅ |
Trivy Kurulumu ve İlk Tarama {#trivy-kurulum}
Linux/macOS Kurulum
# Debian/Ubuntu
sudo apt-get install wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] \
https://aquasecurity.github.io/trivy-repo/deb generic main" | \
sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
# macOS (Homebrew)
brew install trivy
# Docker (platform agnostic)
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image nginx:latest
İlk Image Taraması
# Basit tarama
trivy image nginx:latest
# Sadece CRITICAL ve HIGH vulnerabilities
trivy image --severity CRITICAL,HIGH nginx:latest
# JSON output
trivy image -f json -o results.json nginx:latest
# Ignored CVEs
trivy image --ignore-unfixed nginx:latest # Fix yoksa gösterme
Çıktı Analizi
nginx:latest (debian 12.4)
==========================
Total: 145 (UNKNOWN: 0, LOW: 72, MEDIUM: 54, HIGH: 18, CRITICAL: 1)
┌──────────────┬────────────────┬──────────┬────────────┬─────────────────┐
│ Library │ Vulnerability │ Severity │ Installed │ Fixed Version │
├──────────────┼────────────────┼──────────┼────────────┼─────────────────┤
│ openssl │ CVE-2023-12345 │ CRITICAL │ 3.0.2-1 │ 3.0.2-2 │
│ libcurl4 │ CVE-2023-67890 │ HIGH │ 7.88.1-1 │ 7.88.1-2 │
│ zlib1g │ CVE-2023-11111 │ MEDIUM │ 1:1.2.13 │ 1:1.2.13.1 │
└──────────────┴────────────────┴──────────┴────────────┴─────────────────┘
Image Vulnerability Scanning {#image-scanning}
Local Image Tarama
# Docker daemon'dan image tarama
docker pull redis:7-alpine
trivy image redis:7-alpine
# OCI layout tarama
skopeo copy docker://nginx:latest oci:nginx-oci
trivy image --input nginx-oci
# Tarball tarama
docker save nginx:latest -o nginx.tar
trivy image --input nginx.tar
Private Registry Tarama
# Docker Hub private repo
docker login
trivy image mycompany/private-app:v1.2.3
# AWS ECR
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
trivy image 123456789.dkr.ecr.us-east-1.amazonaws.com/my-app:latest
# Harbor
trivy image --username admin --password Harbor12345 \
harbor.example.com/library/nginx:latest
# Google Container Registry
gcloud auth configure-docker
trivy image gcr.io/my-project/my-app:v1.0.0
Filtreleme ve Raporlama
# Sadece belirli paketleri kontrol et
trivy image --pkg-types os nginx:latest # Sadece OS packages
# Ignored files (node_modules gibi)
cat > .trivyignore << 'EOF'
CVE-2023-12345 # False positive, vendor confirmed
CVE-2023-67890 # Mitigated by network policies
EOF
trivy image --ignorefile .trivyignore nginx:latest
# Template output (custom format)
trivy image --format template --template "@contrib/html.tpl" \
-o report.html nginx:latest
# SARIF format (GitHub Security tab)
trivy image --format sarif -o trivy-results.sarif nginx:latest
Filesystem ve IaC Scanning {#filesystem-iac}
Filesystem (Dependency) Scanning
# Node.js project
trivy fs --scanners vuln ./my-nodejs-app
# Python requirements.txt
trivy fs --security-checks vuln --scanners vuln requirements.txt
# Go module
trivy fs --scanners vuln ./go.mod
# Multi-language project
trivy fs --scanners vuln,misconfig,secret ./my-project
Infrastructure as Code (IaC) Scanning
# Terraform
trivy config ./terraform/
# Kubernetes manifests
trivy config ./k8s-manifests/
# Dockerfile
trivy config --file-patterns "Dockerfile:Dockerfile" ./
# Helm charts
helm template my-app ./charts/my-app | trivy config --stdin
# Example output
./terraform/ec2.tf (terraform)
================================
Tests: 42 (SUCCESSES: 38, FAILURES: 4, EXCEPTIONS: 0)
Failures: 4 (HIGH: 2, MEDIUM: 2, LOW: 0)
HIGH: S3 bucket encryption disabled
─────────────────────────────────────────────────────────────
./terraform/s3.tf:10-15
─────────────────────────────────────────────────────────────
10 ┌ resource "aws_s3_bucket" "data" {
11 │ bucket = "my-data-bucket"
12 │ # Missing: server_side_encryption_configuration
13 └ }
Secret Detection
# Scan for exposed secrets
trivy fs --scanners secret ./my-app
# Common secrets detected:
# - AWS credentials
# - GitHub tokens
# - Private keys
# - API keys
# - Database passwords
# Custom secret patterns
cat > trivy-secret.yaml << 'EOF'
rules:
- id: my-api-key
category: general
title: My Company API Key
severity: CRITICAL
regex: 'MYCOMPANY_API_KEY=[a-zA-Z0-9]{32}'
EOF
trivy fs --secret-config trivy-secret.yaml ./
CI/CD Pipeline Entegrasyonu {#cicd-entegrasyon}
GitHub Actions
# .github/workflows/trivy-scan.yml
name: Container Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
trivy-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # Fail pipeline on vulnerabilities
- name: Upload Trivy results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'
- name: Generate HTML report
if: always()
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'template'
template: '@/contrib/html.tpl'
output: 'trivy-report.html'
- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: trivy-report
path: trivy-report.html
GitLab CI
# .gitlab-ci.yml
stages:
- build
- scan
- deploy
variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t $IMAGE_NAME .
- docker push $IMAGE_NAME
trivy-scan:
stage: scan
image:
name: aquasec/trivy:latest
entrypoint: [""]
script:
- trivy image --exit-code 1 --severity CRITICAL,HIGH $IMAGE_NAME
- trivy image --format json -o trivy-report.json $IMAGE_NAME
artifacts:
reports:
container_scanning: trivy-report.json
paths:
- trivy-report.json
expire_in: 30 days
allow_failure: false
deploy:
stage: deploy
needs: ["trivy-scan"]
script:
- kubectl set image deployment/myapp app=$IMAGE_NAME
only:
- main
Jenkins Pipeline
// Jenkinsfile
pipeline {
agent any
environment {
IMAGE_NAME = "myapp"
IMAGE_TAG = "${env.BUILD_NUMBER}"
}
stages {
stage('Build') {
steps {
script {
docker.build("${IMAGE_NAME}:${IMAGE_TAG}")
}
}
}
stage('Security Scan') {
steps {
script {
sh """
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy:latest image \
--severity CRITICAL,HIGH \
--exit-code 1 \
--format json \
-o trivy-report.json \
${IMAGE_NAME}:${IMAGE_TAG}
"""
}
}
post {
always {
archiveArtifacts artifacts: 'trivy-report.json'
}
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh "kubectl set image deployment/myapp app=${IMAGE_NAME}:${IMAGE_TAG}"
}
}
}
post {
failure {
emailext (
subject: "Security Scan Failed: ${env.JOB_NAME}",
body: "Critical vulnerabilities found. Check artifacts.",
to: "devops@example.com"
)
}
}
}
Kubernetes Cluster Scanning {#kubernetes-scanning}
Cluster-wide Scanning
# Kubeconfig ile cluster tarama
trivy k8s --report summary cluster
# Specific namespace
trivy k8s --namespace production --report all
# Workload scanning
trivy k8s --report all deployment/myapp
# RBAC audit
trivy k8s --report all --components Workload,RBAC
# Output to file
trivy k8s --format json -o cluster-scan.json cluster
Continuous Cluster Monitoring
Trivy Operator Kurulumu:
# Helm ile kurulum
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator \
--namespace trivy-system \
--create-namespace \
--set="trivy.ignoreUnfixed=true"
# CRD'leri kontrol et
kubectl get crd | grep aquasecurity
# Vulnerability reports
kubectl get vulnerabilityreports -A
# Config audit reports
kubectl get configauditreports -A
# Exposed secrets
kubectl get exposedsecretreports -A
VulnerabilityReport Örneği:
apiVersion: aquasecurity.github.io/v1alpha1
kind: VulnerabilityReport
metadata:
name: deployment-nginx-nginx
namespace: default
report:
scanner:
name: Trivy
version: 0.48.0
summary:
criticalCount: 0
highCount: 2
mediumCount: 15
lowCount: 43
vulnerabilities:
- vulnerabilityID: CVE-2023-12345
resource: openssl
installedVersion: 3.0.2-1
fixedVersion: 3.0.2-2
severity: HIGH
title: Buffer overflow in OpenSSL
Admission Controller (Policy Enforcement)
# Webhook tabanlı policy enforcement
helm install trivy-admission aqua/trivy-admission \
--namespace trivy-system \
--set policy.enforcementLevel=high \
--set policy.blockOnCritical=true
# Test deployment (CRITICAL varsa reddedilir)
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: vulnerable-app
spec:
replicas: 1
selector:
matchLabels:
app: vulnerable
template:
metadata:
labels:
app: vulnerable
spec:
containers:
- name: app
image: nginx:1.14 # Old version with CVEs
EOF
# Error: admission webhook denied the request:
# Critical vulnerabilities found: CVE-2023-xxxxx
Container Image Hardening {#image-hardening}
Minimal Base Images
# ❌ Büyük ve vulnerability'li
FROM ubuntu:22.04 # 77 MB, 100+ packages
RUN apt-get update && apt-get install -y python3 python3-pip
COPY . /app
CMD ["python3", "app.py"]
# ✅ Minimal distroless
FROM python:3.11-slim # 45 MB
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]
# ✅ En güvenli: Google Distroless
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM gcr.io/distroless/python3-debian12 # 25 MB, shell yok!
COPY /root/.local /root/.local
COPY . /app
WORKDIR /app
ENV PATH=/root/.local/bin:$PATH
CMD ["app.py"]
Distroless avantajları:
- Shell yok (no remote access)
- Package manager yok (no runtime changes)
- Minimal attack surface
- %70 daha az vulnerability
Non-Root User
# ❌ Root kullanıcı
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
# ✅ Non-root user
FROM node:18-alpine
RUN addgroup -g 1001 -S appgroup && \
adduser -u 1001 -S appuser -G appgroup
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
USER appuser
EXPOSE 3000
CMD ["node", "server.js"]
Security Best Practices
# ✅ Production-ready Dockerfile
FROM node:18-alpine AS builder
# Non-root user
RUN addgroup -g 1001 nodejs && adduser -u 1001 -G nodejs -s /bin/sh -D nodejs
WORKDIR /app
# Dependencies önce (layer caching)
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# Application code
COPY . .
# Build artifacts
RUN npm run build
# Final stage: distroless
FROM gcr.io/distroless/nodejs18-debian12
COPY /etc/passwd /etc/passwd
COPY /etc/group /etc/group
COPY /app/dist /app
COPY /app/node_modules /app/node_modules
WORKDIR /app
USER nodejs
EXPOSE 3000
CMD ["index.js"]
# Metadata
LABEL org.opencontainers.image.source="https://github.com/myorg/myapp"
LABEL org.opencontainers.image.description="My secure Node.js app"
LABEL org.opencontainers.image.licenses="MIT"
Multi-Stage Builds ve Minimal Base Images {#multi-stage}
Go Application (Scratch Base)
# Multi-stage Go build
FROM golang:1.21-alpine AS builder
WORKDIR /app
# Dependencies
COPY go.mod go.sum ./
RUN go mod download
# Build
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o main .
# Final stage: scratch (0 MB base!)
FROM scratch
# CA certificates (HTTPS için gerekli)
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Binary
COPY /app/main /main
# Non-root user (scratch'te manuel)
USER 65534:65534
ENTRYPOINT ["/main"]
# Final image: ~10 MB (sadece binary + certs)
Trivy scan sonucu:
scratch:latest (unknown)
========================
Total: 0 (CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0)
Python Application (Distroless)
FROM python:3.11-slim AS builder
WORKDIR /app
# System dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
# Python dependencies
COPY requirements.txt .
RUN pip install --user --no-cache-dir --no-warn-script-location -r requirements.txt
# Final stage
FROM gcr.io/distroless/python3-debian12
# Copy dependencies
COPY /root/.local /root/.local
# Copy application
COPY app/ /app/
WORKDIR /app
ENV PATH=/root/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
USER nonroot
CMD ["main.py"]
Supply Chain Security ve SBOM {#supply-chain}
Software Bill of Materials (SBOM)
# SBOM oluşturma (CycloneDX format)
trivy image --format cyclonedx --output sbom.json nginx:latest
# SPDX format
trivy image --format spdx-json --output sbom-spdx.json nginx:latest
# SBOM'dan vulnerability tarama
trivy sbom sbom.json
# SBOM comparison (dependency diff)
trivy image --format cyclonedx --output old-sbom.json myapp:v1.0.0
trivy image --format cyclonedx --output new-sbom.json myapp:v2.0.0
# Manual diff veya SBOM diff tools kullanarak değişiklikleri inceleyin
Image Signing (Cosign)
# Install Cosign
brew install sigstore/tap/cosign
# Generate keypair
cosign generate-key-pair
# Sign image
cosign sign --key cosign.key myregistry.io/myapp:v1.0.0
# Verify signature
cosign verify --key cosign.pub myregistry.io/myapp:v1.0.0
# Kubernetes admission controller ile imzasız image'ları reddet
Dependency Tracking
# Version pinning (reproducible builds)
# ❌ Unstable versions
FROM node:latest
RUN apt-get install -y curl # Any version
# ✅ Pinned versions
FROM node:18.19.0-alpine3.19@sha256:abc123...
RUN apk add --no-cache curl=8.5.0-r0
# ✅ Lock files
COPY package-lock.json . # npm
COPY Pipfile.lock . # Python
COPY go.sum . # Go
COPY Cargo.lock . # Rust
Kubernetes Security Context {#security-context}
Pod Security Standards
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
replicas: 3
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
# Pod-level security
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:v1.0.0
# Container-level security
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # Only if needed
# Resource limits (DoS protection)
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: "0.5"
memory: 256Mi
# Health checks
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# Writable volumes (minimal)
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
# Namespace-level Pod Security
# (Enforced by PodSecurity admission controller)
Pod Security Admission
# Namespace with Pod Security Standards
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
Runtime Security: Falco Integration {#runtime-security}
Falco Kurulumu
# Helm ile Falco kurulumu
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace \
--set tty=true \
--set falco.json_output=true
# Falco rules
kubectl get cm -n falco falco-rules -o yaml
Custom Falco Rules
# Suspicious shell activity detection
- rule: Shell in Container
desc: Detect shell spawned in container
condition: >
spawned_process and
container and
proc.name in (bash, sh, zsh, fish) and
not container.image.repository in (builder_images)
output: >
Shell spawned in container
(user=%user.name container=%container.name
image=%container.image.repository:%container.image.tag
command=%proc.cmdline)
priority: WARNING
# Sensitive file access
- rule: Read Sensitive File
desc: Detect reads of sensitive files
condition: >
open_read and
container and
fd.name in (/etc/shadow, /etc/sudoers, /root/.ssh/id_rsa)
output: >
Sensitive file opened for reading
(user=%user.name file=%fd.name container=%container.name)
priority: CRITICAL
Policy Enforcement: OPA ve Kyverno {#policy-enforcement}
Kyverno Policies
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-image-scanning
spec:
validationFailureAction: Enforce
background: true
rules:
- name: check-trivy-scan-results
match:
any:
- resources:
kinds:
- Pod
validate:
message: >
Container image must be scanned by Trivy.
No CRITICAL or HIGH vulnerabilities allowed.
deny:
conditions:
any:
- key: "{{ request.object.metadata.annotations.\"trivy.vulnerability.count.CRITICAL\" || '0' }}"
operator: GreaterThan
value: 0
- key: "{{ request.object.metadata.annotations.\"trivy.vulnerability.count.HIGH\" || '0' }}"
operator: GreaterThan
value: 5
- name: require-non-root
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Containers must run as non-root user"
pattern:
spec:
containers:
- securityContext:
runAsNonRoot: true
- name: disallow-privileged
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Privileged containers are not allowed"
pattern:
spec:
containers:
- =(securityContext):
=(privileged): false
Production Best Practices {#best-practices}
1. Automated Scanning Workflow
Developer Push → GitHub → CI Build → Trivy Scan → Results
↓
Pass/Fail
↓
├─ PASS: Deploy to Registry
└─ FAIL: Block + Notify
2. Vulnerability Severity Thresholds
# .trivy.yaml (project config)
severity:
- CRITICAL
- HIGH
ignoreUnfixed: true
policy:
critical:
action: fail
max: 0
high:
action: fail
max: 5
medium:
action: warn
max: 20
3. Registry Integration
# Harbor: Automatic scanning on push
# ECR: Scan on push enabled
aws ecr put-image-scanning-configuration \
--repository-name myapp \
--image-scanning-configuration scanOnPush=true
# GCR: Container Analysis API
gcloud services enable containeranalysis.googleapis.com
4. Continuous Monitoring
# Scheduled cluster scans (CronJob)
apiVersion: batch/v1
kind: CronJob
metadata:
name: trivy-cluster-scan
namespace: security
spec:
schedule: "0 2 * * *" # Daily 02:00
jobTemplate:
spec:
template:
spec:
serviceAccountName: trivy-scanner
containers:
- name: trivy
image: aquasec/trivy:latest
args:
- k8s
- --report
- all
- cluster
volumeMounts:
- name: kubeconfig
mountPath: /root/.kube
restartPolicy: OnFailure
volumes:
- name: kubeconfig
secret:
secretName: kubeconfig
5. Incident Response Workflow
Vulnerability Detected
↓
CRITICAL?
├─ YES: Page on-call, emergency patch
└─ NO: Create ticket, plan update
↓
Patch Available?
├─ YES: Build new image, test, deploy
└─ NO: Mitigation (network policies, WAF rules)
↓
Verify fix with Trivy
↓
Document in postmortem
Monitoring ve Alerting {#monitoring}
Prometheus Metrics (Trivy Operator)
# ServiceMonitor for Trivy Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: trivy-operator
namespace: trivy-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: trivy-operator
endpoints:
- port: metrics
interval: 30s
# Prometheus alerts
groups:
- name: trivy-alerts
rules:
- alert: CriticalVulnerability
expr: trivy_vulnerability_count{severity="CRITICAL"} > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Critical vulnerability detected"
description: "{{ $labels.namespace }}/{{ $labels.pod }} has {{ $value }} CRITICAL vulnerabilities"
- alert: HighVulnerabilityThreshold
expr: trivy_vulnerability_count{severity="HIGH"} > 10
for: 15m
labels:
severity: warning
annotations:
summary: "High vulnerability count"
description: "{{ $labels.namespace }} has {{ $value }} HIGH vulnerabilities"
Grafana Dashboard
{
"dashboard": {
"title": "Container Security - Trivy",
"panels": [
{
"title": "Vulnerabilities by Severity",
"targets": [
{
"expr": "sum by (severity) (trivy_vulnerability_count)"
}
],
"type": "piechart"
},
{
"title": "Most Vulnerable Images",
"targets": [
{
"expr": "topk(10, sum by (image_repository) (trivy_vulnerability_count{severity=\"CRITICAL\"}))"
}
],
"type": "table"
},
{
"title": "Scan Success Rate",
"targets": [
{
"expr": "rate(trivy_scan_total{status=\"success\"}[5m]) / rate(trivy_scan_total[5m])"
}
],
"type": "stat"
}
]
}
}
Sonuç
Container security, modern DevOps pipeline'ının vazgeçilmez bir parçası. Bu yazıda ele aldığımız konuları özetleyelim:
Temel Prensipler
✅ Shift-Left Security: Vulnerability'leri production'a gitmeden önce yakala
✅ Automation: CI/CD pipeline'ında otomatik scanning
✅ Minimal Attack Surface: Distroless images, non-root users
✅ Defense in Depth: Build-time + runtime security layers
✅ Continuous Monitoring: Cluster-wide vulnerability tracking
✅ Supply Chain Security: SBOM, image signing, dependency tracking
Bir Sonraki Adımlar
- Trivy'yi CI/CD'ye entegre edin (GitHub Actions, GitLab CI)
- Base image'lerinizi minimal image'lere taşıyın (Alpine, Distroless, Scratch)
- Kubernetes security context'leri sertleştirin
- Trivy Operator ile cluster monitoring kurun
- SBOM oluşturmaya başlayın (compliance ve audit için)
- Policy enforcement ekleyin (Kyverno, OPA Gatekeeper)
Container security bir yolculuk, hedef değil. Sürekli güncelleme, monitoring ve iyileştirme gerektirir. Trivy gibi araçlar bu yolculuğu kolaylaştırır ve ekibinize proactive güvenlik kültürü kazandırır.
Sorularınız veya geri bildirimleriniz mi var? LinkedIn üzerinden bizimle iletişime geçin veya GitHub repo'larımıza katkıda bulunun!
Bir sonraki yazıda görüşmek üzere! 🚀🔒