Container Security Guide

Secure Dockerfile

# Use specific, minimal base image FROM gcr.io/distroless/static-debian12:nonroot # NOT: FROM ubuntu:latest # Multi-stage build to minimize final image FROM golang:1.22-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o server . FROM gcr.io/distroless/static-debian12:nonroot COPY --from=builder /app/server /server # Run as non-root USER nonroot:nonroot # Read-only root filesystem # (set in K8s securityContext instead) EXPOSE 8080 ENTRYPOINT ["/server"]

Kubernetes Security Context

apiVersion: apps/v1 kind: Deployment spec: template: spec: # Pod-level security securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 1000 fsGroup: 1000 seccompProfile: type: RuntimeDefault containers: - name: app securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] add: [] # add only what's needed volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {}

Image Scanning

# Trivy (scan image for CVEs) trivy image myregistry/myapp:latest # Scan and fail on HIGH/CRITICAL trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest # Scan Dockerfile (misconfigurations) trivy config ./Dockerfile # In CI (GitHub Actions) # - uses: aquasecurity/trivy-action@master # with: # image-ref: myapp:${{ github.sha }} # severity: CRITICAL,HIGH # exit-code: 1 # Snyk snyk container test myapp:latest