Security
Intermediate 17 min read Security

Container Security

Containers share the host kernel, so their security posture matters enormously. Learn to pick safe base images, run as non-root, drop capabilities, and scan images in the pipeline.

non-rootcapabilitiesseccompimage scanningsupply chaindistroless
Introduction

What is this?

Container security is about shrinking the attack surface of the image and the privileges of the running process. Key levers: minimal base images, non-root users, dropping Linux capabilities, seccomp profiles, read-only filesystems and continuous image scanning. Because containers share the host kernel, a container escape is a host compromise.

Motivation

Why do you need it?

  • A container running as root that escapes the namespace becomes root on the host — the worst-case blast radius.
  • Attackers scan registries for default images with known vulnerabilities; every unpatched package is a foothold.
  • The supply chain is the vector: compromised base images and dependencies poison every build that uses them.
  • Images are immutable and versioned, so scanning them is a reproducible, automatable gate.
  • Orchestrators amplify mistakes: one bad image deployed everywhere is one big incident.
Think about it

Mental model

Imagine

A security guard in a sealed booth

Think of

A container

The booth (container) keeps the guard (app) separated from the building (host), but only if the booth has its own locked door — non-root user, dropped capabilities, sealed filesystem.

Mechanics

How it works

  • The base image defines the attack surface: distroless and scratch minimize what an attacker can run inside.
  • USER in the Dockerfile makes the container run as a non-root user, so escape does not equal root.
  • Linux capabilities and seccomp profiles strip the kernel operations a process may perform.
  • A read-only root filesystem plus tmpfs for scratch data prevents persistent tampering.
  • Scanners (Trivy, Grype) compare image contents against vulnerability databases and fail the build on criticals.

Hardening layers for a container runtime.

Minimal base
Non-root USER
Capabilities
seccomp + read-only
Scan every build
Reference

Key commands

trivy image --severity HIGH,CRITICAL myapp:1.0

Scan an image for known vulnerabilities and filter to the serious ones.

docker run --rm --user 1000:1000 nginx:alpine id

Run as an unprivileged user to prove the app works non-root.

docker run --read-only --tmpfs /tmp --cap-drop ALL myapp:1.0

Enforce a read-only root filesystem and drop all capabilities.

docker history myapp:1.0

Inspect layers to spot bloated or suspicious additions.

docker scout cves myapp:1.0

Use Docker Scout to surface CVEs in a local image.

Hands-on

Examples

Scan an image in your pipeline

Scan an image in your pipeline
trivy image --severity HIGH,CRITICAL --no-progress myapp:1.0
trivy image --format sarif --output trivy.sarif myapp:1.0
docker run --rm --user 1000:1000 --read-only --cap-drop ALL myapp:1.0

The first line gates the build on high/critical CVEs, the second emits SARIF for the security dashboard, and the third proves the image still runs with a locked-down runtime profile.

Real world

In production

  • Every PR builds and scans the image; HIGH/CRITICAL findings block merge and promotion.
  • Production images use distroless or scratch bases with no shell, reducing exploitability.
  • Kubernetes enforces securityContext (runAsNonRoot, readOnlyRootFilesystem, seccomp) on every pod.
  • Signatures (cosign) and pinned base digests protect the supply chain end to end.
  • An SBOM is generated at build time and attached to the artifact for compliance and incident response.
Guidelines

Best practices

  • Run as a non-root user; set USER in the Dockerfile and runAsNonRoot in Kubernetes.
  • Use minimal, pinned base images — never float on :latest tags.
  • Drop all capabilities and re-add only the ones the app genuinely needs.
  • Make the filesystem read-only and mount scratch space for writes.
  • Scan images and their dependencies continuously, gating promotions on severity.
Watch out

Common mistakes

  • Running containers as root because the app needs port 80.
  • Building on fat base images that carry shells and compilers into production.
  • Scanning images only at build time, never monitoring the registry for new CVEs.
  • Copying secrets into images via ENV or build args.
  • Ignoring third-party base images from unknown publishers.
Root cause analysis

Common issues

Error
Container fails to start after adding --read-only
Root cause

The app writes to a path in the root filesystem

Fix

Identify the write path from the error, mount it as a volume/tmpfs, or use an app that writes only to /tmp.

Error
Bind to port 80 fails as non-root
Root cause

Unprivileged processes cannot bind ports below 1024 without NET_BIND_SERVICE

Fix

Listen on 8080 and map it, or add the single NET_BIND_SERVICE capability.

Error
Scanner reports CVEs in the OS layer
Root cause

The base image is out of date

Fix

Rebuild on the latest pinned base digest and re-scan; pin by digest so updates are deliberate.

When things break

Debugging tips

  • Scan the base image and the final image separately to localize which layer introduced a CVE.
  • Use trivy image --severity and --ignore-unfixed to separate real risk from noise.
  • Test a locked-down image with docker run --cap-drop ALL --read-only and read the error to find what is missing.
  • Compare image digests between environments to confirm drift did not change the security posture.
Interviews

Interview checkpoint

Practice

Hands-on lab

Harden a Container Image
30 min · intermediate
In progress
Objectives
  • Build an image with a baked-in secret
  • Prove the secret is visible at runtime
  • Run containers with a hardened runtime profile
  • Verify identity inside the container

Harden a Container Image

30 min · intermediate

0/6 steps
0%
sandbox · Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

What is the primary reason containers should not run as root?

2

An image with fewer layers is inherently more secure.

3

When should image scanning happen to be most effective?

Quick reference

Cheat sheet

Hardening flags
--user 1000:1000Run as an unprivileged user
--read-only --tmpfs /tmpSeal the root filesystem
--cap-drop ALLRemove every capability
--cap-add NET_BIND_SERVICERe-add only what is needed
Scanning
trivy image IMGScan a local image
trivy image --severity HIGH,CRITICALFilter to serious CVEs
trivy image --format sarifEmit SARIF for dashboards
docker scout cves IMGDocker-native CVE report
Go deeper

Official documentation