Skip to content
Hogin Hogin
Go back

Container Security: A Practical Checklist for Implementation

Updated:
2 мин чтения

Containers are a powerful tool, but misconfiguring them is often the cause of leaks and compromises. Below is a step-by-step checklist with examples that you can apply directly to your Docker and Kubernetes projects.


1. Build: Multi-stage and Minimal Images

Why:
The fewer packages and libraries inside a container, the fewer potential vulnerabilities.

Example:
A Go application without a multi-stage build:

FROM golang:1.22
WORKDIR /app
COPY . .
RUN go build -o app
CMD ["./app"]

Such an image will weigh ~1 GB, with lots of unnecessary packages.

With multi-stage:

# Build stage
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o app

# Runtime stage
FROM gcr.io/distroless/base
COPY --from=builder /app/app /
USER nonroot:nonroot
CMD ["/app"]

The final image will weigh <100 MB and contain only the binary.


2. Runtime: Only Non-Privileged Users

Why:
Running as root inside a container = if an attacker escapes the container, they gain root on the node.

Example in a Dockerfile:

RUN adduser -u 1001 --disabled-password appuser
USER appuser

Example in Kubernetes:

securityContext:
  runAsUser: 1001
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

3. Policies: Pod Security Admission

Why:
PSA automatically blocks the launch of insecure pods (for example, those with root privileges).

Example:
Enable the baseline policy at the namespace level:

apiVersion: v1
kind: Namespace
metadata:
  name: secure-ns
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: baseline
    pod-security.kubernetes.io/warn: baseline

If a developer tries to run a Pod with privileged: true, Kubernetes simply won’t start it.


4. Scanning: Trivy in CI/CD

Why:
CI/CD should block the deployment of vulnerable images.

Example in GitLab CI:

stages:
  - build
  - security

build_image:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .

scan_image:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

If Trivy finds critical vulnerabilities, the pipeline will fail.


5. Network Policies: NetworkPolicy

Why:
By default, all pods in Kubernetes can talk to each other. This is a huge risk.

Example: the API can reach the DB, but not the other way around:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-api
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
  policyTypes:
    - Ingress

Now nothing except api will be able to connect to PostgreSQL.


Conclusion

If you implement these five steps:
✅ Minimal images
✅ Running without root
✅ Pod Security Admission
✅ Automated scanning
✅ NetworkPolicy

— you’ll close off 80% of typical container security mistakes.


Share this post:

Next Post
Backing Up Databases and Files to S3 with Restic + Healthchecks