Container Security
Harden what you ship β from the base image to the running Pod.
Containers are how modern software ships, so securing them is essential. Container security spans the whole lifecycle: the image you build, the scan before you ship, and the runtime settings that constrain a container in production. This lesson ties DevSecOps back to the Docker and Kubernetes skills you already have.
π― Learning Objectives
By the end of this lesson you will:
- Build minimal, hardened container images
- Run containers as a non-root user
- Scan images for vulnerabilities in CI
- Apply Kubernetes security context and policies
Start with a Minimal Image
The smaller the image, the smaller the attack surface. Every extra package is a potential vulnerability.
| Choice | Attack surface |
|---|---|
Full OS image (e.g. ubuntu) |
Large β many packages, shells, tools |
Slim image (e.g. -slim) |
Smaller |
Alpine (e.g. node:20-alpine) |
Small |
| Distroless / scratch | Minimal β no shell, no package manager |
π‘ No shell, no shell exploits
Distroless images contain only your app and its runtime β no shell, no package manager. An attacker who breaks in finds almost nothing to work with. Itβs one of the highest-value hardening steps.
Never Run as Root
By default containers run as root. If an attacker escapes the app, root inside the container is a dangerous starting point. Drop to a non-root user:
FROM node:20-slim
# Create and switch to a non-root user
RUN useradd --system --uid 1001 appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
RUN npm ci --production
USER appuser # everything below runs as appuser
EXPOSE 3000
CMD ["node", "server.js"]β Root in a container is root-adjacent on the host
A container running as root that suffers a breakout has a far easier path to compromising the host. Running as an unprivileged user is one of the single most effective container hardening measures.
Scan Images in CI
Base images and dependencies accumulate known vulnerabilities over time. Scan every image before it ships:
# Fail the build on high/critical image vulnerabilities
trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:1.0π‘ Rebuild regularly
Even if your code doesnβt change, rebuild images periodically to pick up patched base layers. An image built six months ago likely carries vulnerabilities fixed since.
Harden the Runtime in Kubernetes
Securing the image isnβt enough β constrain the container at runtime too, using a securityContext:
spec:
containers:
- name: app
image: myapp:1.0
securityContext:
runAsNonRoot: true # refuse to run as root
runAsUser: 1001
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true # filesystem is immutable
capabilities:
drop: ["ALL"] # drop all Linux capabilitiesEach setting shrinks what a compromised container can do:
runAsNonRoot/runAsUserβ no root.allowPrivilegeEscalation: falseβ canβt gain more privileges.readOnlyRootFilesystemβ attacker canβt write malware to disk.drop: ["ALL"]β remove Linux capabilities the app doesnβt need.
π‘ Enforce cluster-wide
Use Pod Security Standards or a policy engine (like Kyverno or OPA Gatekeeper) to enforce these settings across the whole cluster, so no one can deploy an unhardened container by accident.
π§ͺ Hands-on Lab
Harden a Container End to End
- Rewrite a Dockerfile to use a slim base and a non-root user
- Add a CI step that scans the image and fails on HIGH/CRITICAL
- Write a Kubernetes securityContext that enforces non-root and a read-only filesystem
π§ Knowledge Check
Why is running a container as a non-root user an important security measure?
What does readOnlyRootFilesystem: true achieve in a Kubernetes securityContext?
πΌ Interview Preparation
How do you secure containers across their lifecycle?
π Course Complete
Congratulations β youβve worked through the full DevOps journey: Networking, Docker, Kubernetes, Terraform, GitHub Actions, Jenkins, Agentic AI, and DevSecOps, on top of the Linux, Git, and cloud foundations. You now have the vocabulary, the hands-on patterns, and the interview answers of a production-ready DevOps engineer.
The best next step is to build: combine these skills into a real project β containerise an app, provision its infrastructure with Terraform, ship it through a secure CI/CD pipeline onto Kubernetes, and monitor it. Thatβs where everything clicks together.