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