Skip to main content

Module 3: Containers & Workload Security

Hardening containers from image build to runtime with Pod Security Standards, seccomp, and distroless images

3 hours. 3 hands-on labs. Free course module.

Learning Objectives

  • Understand Linux container isolation primitives (namespaces, cgroups)
  • Build secure container images with distroless and rootless patterns
  • Configure Pod Security Standards for cluster-wide enforcement
  • Implement seccomp and capabilities restrictions

Why This Matters

Container escapes are the most impactful Kubernetes attacks — breaking out of a container gives the attacker access to the node and potentially the entire cluster. Proper container hardening is the first line of defense and the most frequently misconfigured.

CONTAINER ISOLATION vs CONTAINER ESCAPEProperly Isolated ContainerPID NamespaceNetwork NamespaceMount NamespaceUser NamespaceSeccomp + AppArmor + Capabilities DropNon-root user | Read-only FS | No hostPIDResult: strong isolation from hostContainer Escape Scenarioprivileged: true (ALL capabilities)hostPID: true (sees host processes)hostNetwork: true (host network stack)Root user | Writable FS | No seccompResult: trivial escape to host
Architecture diagram for Module 3: Containers & Workload Security.

Lesson Content

Containers are not VMs. They share the host kernel and rely on Linux primitives — namespaces, cgroups, seccomp, capabilities — for isolation. Misconfigure any of these, and the container boundary dissolves.

Linux Container Isolation Primitives

  • Namespaces: Isolate what a container can see (PID, network, mount, user, IPC, UTS)
  • cgroups: Limit what a container can use (CPU, memory, I/O)
  • Seccomp: Filter which syscalls a container can make (block dangerous ones like ptrace, mount)
  • Capabilities: Fine-grained root privileges (drop everything except what is needed)
  • AppArmor/SELinux: Mandatory access control for file and network operations

Secure Container Image Patterns

# Insecure: full OS, root user, unnecessary tools
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl wget vim
COPY app /app
CMD ["/app"]

# Secure: distroless, non-root, minimal attack surface
FROM gcr.io/distroless/static-debian12:nonroot
COPY --chown=65534:65534 app /app
USER 65534
ENTRYPOINT ["/app"]
# No shell, no package manager, no curl, no wget
# Attacker with RCE cannot spawn a shell

Pod Security Standards

Kubernetes defines three Pod Security Standards that enforce container hardening at the namespace level:

  • Privileged: No restrictions (for system workloads only)
  • Baseline: Prevents known privilege escalations (blocks hostPID, hostNetwork, privileged)
  • Restricted: Maximum hardening (requires non-root, read-only root FS, drops ALL capabilities)
# Enforce restricted Pod Security Standard on a namespace
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted

Real-World Use Cases

  • Hardening container images for production
  • Implementing Pod Security Standards cluster-wide
  • Building distroless CI pipelines
  • Container escape prevention in multi-tenant clusters

Production Notes

  • Use distroless or scratch base images for all production workloads. A container with no shell cannot be used for interactive exploitation.
  • Apply the restricted Pod Security Standard to all production namespaces. Use warn mode first to identify non-compliant workloads before enforcing.

Common Mistakes

  • Running containers as root (the default in most base images)
  • Using ubuntu or alpine base images that include shells and package managers
  • Not dropping ALL capabilities and adding back only what is needed
  • Setting privileged: true "just to make it work" and never removing it
  • Not enforcing Pod Security Standards on production namespaces

Security Risks to Watch

  • privileged: true gives the container ALL capabilities including CAP_SYS_ADMIN — equivalent to root on the host
  • hostPID exposes all host processes to the container — enables credential theft from other pods
  • hostNetwork puts the container on the host network stack — bypasses all NetworkPolicies

Production Story

A container running as root with hostPID was used by an attacker to read K8s secrets from kubelet process memory. After enforcing Pod Security Standards cluster-wide, privileged containers were blocked before reaching production.

Career Relevance

Container hardening is foundational for any K8s security role. Organizations need engineers who build secure-by-default container pipelines.

Key Terms

Namespace (Linux)
Kernel feature that isolates what a process can see (PID, network, mount, etc.)
cgroup
Control group — limits CPU, memory, and I/O resources for a set of processes
Seccomp
Secure computing mode — filters which syscalls a process can make
Distroless
Container image containing only the application binary and runtime — no OS tools
Pod Security Standard
Kubernetes policy level (Privileged/Baseline/Restricted) for container hardening

Hands-On Labs

  1. Harden an Insecure Container

    Transform an insecure Dockerfile into a hardened production image.

    30 min - Beginner

    • Start with a vulnerable Dockerfile (root, full OS, unnecessary tools)
    • Rebuild with distroless base image
    • Add non-root user and read-only filesystem
    • Compare image sizes and attack surfaces

    View lab files on GitHub

  2. Configure Pod Security Standards

    Enforce container hardening at the namespace level.

    25 min - Beginner

    • Label a namespace with restricted Pod Security Standard
    • Deploy a compliant pod (succeeds)
    • Deploy a non-compliant pod with hostPID (rejected)
    • Review audit logs for policy violations

    View lab files on GitHub

  3. Container Escape Demonstration

    Understand how misconfigurations enable container escape.

    30 min - Intermediate

    • Deploy a privileged container with hostPID
    • Access host processes from inside the container
    • Read host filesystem via /proc/1/root
    • Fix the configuration and verify isolation is restored

    View lab files on GitHub

Key Takeaways

  • Containers share the host kernel — isolation depends on namespaces, cgroups, seccomp
  • Distroless images eliminate shells and tools, drastically reducing attack surface
  • Pod Security Standards enforce container hardening at the namespace level
  • Never run containers as root or with privileged: true in production
  • Seccomp profiles block dangerous syscalls — always enable the default profile