# ARTICLE_LOADED
> cat container-security-trivy-image-scanning.md
> rendering content...
status: READING_MODE
security_level: PUBLIC
engagement_tracking: ENABLED
article@tektik:/var/blog/container-security-trivy-image-scanning$
cat metadata.json
"category": "DevOps"
"date": "2026-03-09"
"read_time": "18 dk okuma"
"author": "TekTık Yazılım DevOps Ekibi"
DevOps9 Mart 2026

Container Security: Kubernetes'te Güvenli Container İmajları ile Çalışma

echo"Container güvenliği neden kritik? Trivy ile vulnerability scanning, image hardening, supply chain security ve Kubernetes'te güvenli container deployment için production-ready stratejiler."
#Container Security#Kubernetes#Trivy#DevOps#Docker#Security#Supply Chain#CI/CD
18 dk okuma
TekTık Yazılım DevOps Ekibi
content@tektik:/var/articles/container-security-trivy-image-scanning.md$
./render-article --format=html --style=cyber

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

  1. Container Security'ye Giriş
  2. Container Güvenlik Riskleri
  3. Trivy Nedir ve Neden Kullanmalıyız?
  4. Trivy Kurulumu ve İlk Tarama
  5. Image Vulnerability Scanning
  6. Filesystem ve IaC Scanning
  7. CI/CD Pipeline Entegrasyonu
  8. Kubernetes Cluster Scanning
  9. Container Image Hardening
  10. Multi-Stage Builds ve Minimal Base Images
  11. Supply Chain Security ve SBOM
  12. Kubernetes Security Context
  13. Runtime Security: Falco Integration
  14. Policy Enforcement: OPA ve Kyverno
  15. Production Best Practices
  16. 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ı

text
┌─────────────────────────────────────┐
│   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)

bash
# Ö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

dockerfile
# ❌ Kötü pratikler
FROM node:latest  # Unstable, unpredictable
USER root  # Root privilege
COPY --chown=root:root . /app  # Root ownership

3. Secrets in Images

dockerfile
# ❌ 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

yaml
# ❌ 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

ToolCoverageSpeedK8s SupportFree
**Trivy**⭐⭐⭐⭐⭐⚡⚡⚡
Grype⭐⭐⭐⭐⚡⚡⚡⚠️
Snyk⭐⭐⭐⭐⭐⚡⚡Limited
Clair⭐⭐⭐⚡⚡

Trivy Kurulumu ve İlk Tarama {#trivy-kurulum}

Linux/macOS Kurulum

bash
# 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ı

bash
# 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

text
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

bash
# 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

bash
# 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

bash
# 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

bash
# 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

bash
# 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

bash
# 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

yaml
# .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

yaml
# .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

groovy
// 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

bash
# 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:

bash
# 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:

yaml
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)

bash
# 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

dockerfile
# ❌ 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 --from=builder /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

dockerfile
# ❌ 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 --chown=appuser:appgroup package*.json ./
RUN npm ci --only=production

COPY --chown=appuser:appgroup . .

USER appuser
EXPOSE 3000
CMD ["node", "server.js"]

Security Best Practices

dockerfile
# ✅ 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 --chown=nodejs:nodejs . .

# Build artifacts
RUN npm run build

# Final stage: distroless
FROM gcr.io/distroless/nodejs18-debian12

COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group
COPY --from=builder --chown=nodejs:nodejs /app/dist /app
COPY --from=builder --chown=nodejs:nodejs /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)

dockerfile
# 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 --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

# Binary
COPY --from=builder /app/main /main

# Non-root user (scratch'te manuel)
USER 65534:65534

ENTRYPOINT ["/main"]

# Final image: ~10 MB (sadece binary + certs)

Trivy scan sonucu:

text
scratch:latest (unknown)
========================
Total: 0 (CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0)

Python Application (Distroless)

dockerfile
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 --from=builder /root/.local /root/.local

# Copy application
COPY --chown=nonroot:nonroot 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)

bash
# 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)

bash
# 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

dockerfile
# 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

yaml
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

yaml
# 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

bash
# 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

yaml
# 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

yaml
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

text
Developer Push → GitHub → CI Build → Trivy Scan → Results
                                        ↓
                                   Pass/Fail
                                        ↓
                                   ├─ PASS: Deploy to Registry
                                   └─ FAIL: Block + Notify

2. Vulnerability Severity Thresholds

yaml
# .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

bash
# 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

bash
# 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

text
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)

yaml
# 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

json
{
  "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

  1. Trivy'yi CI/CD'ye entegre edin (GitHub Actions, GitLab CI)
  2. Base image'lerinizi minimal image'lere taşıyın (Alpine, Distroless, Scratch)
  3. Kubernetes security context'leri sertleştirin
  4. Trivy Operator ile cluster monitoring kurun
  5. SBOM oluşturmaya başlayın (compliance ve audit için)
  6. 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! 🚀🔒