Container Security: Image Hardening and Runtime Protection
Harden Docker images by removing unnecessary packages, running as non-root, and using runtime security tools (Falco, Sysdig) to detect anomalous container behavior.
Container Security: Image Hardening and Runtime Protection is a free Cloud & IT Cert Prep lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Cloud & IT Cert Prep learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Container Security Fundamentals
Containers package application code and its dependencies into isolated units that share the host OS kernel, unlike VMs which include a full guest OS. This sharing makes containers lightweight and fast, but introduces a different security model: a container escape vulnerability could allow an attacker to break out of the container and access the host kernel directly, affecting all other containers. Container security focuses on three layers: the image (what is baked in), the runtime (what the container can do while running), and the orchestration platform (how containers are managed).
Minimal Base Images: Reducing Attack Surface
Every package installed in a container image is a potential attack surface. The principle of minimal base images means starting from the smallest possible foundation: Alpine Linux (5MB, minimal packages), distroless images (Google's images that contain only the runtime and application, no shell or package manager), or scratch (completely empty, for statically compiled binaries). A container with no shell means an attacker who achieves code execution cannot easily run wget, curl, or other tools to escalate their attack — a principle called defense through minimal exposure.
# Bad: starts from a full OS image
FROM ubuntu:22.04
# Better: minimal Alpine base
FROM alpine:3.18
# Best: distroless for Java apps
FROM gcr.io/distroless/java17-debian11Running as Non-Root: The First Rule
By default, Docker containers run as root (UID 0). If an attacker exploits a vulnerability in the containerized application, they gain root privileges inside the container. If the container shares a volume or has host mounts, root inside the container can equal root on the host. The fix is simple: create a dedicated user in the Dockerfile and switch to it with the USER directive before the final CMD/ENTRYPOINT. Many container security scanning tools will flag any image without a non-root user as a finding.
FROM alpine:3.18
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --chown=appuser:appgroup app /app/app
USER appuser
CMD ["/app/app"]Immutable Containers and Read-Only Filesystems
Immutable containers are containers whose filesystem cannot be modified at runtime. Enabling --read-only in Docker (or readOnlyRootFilesystem: true in Kubernetes) prevents attackers from writing malware to disk, modifying configuration files, or installing tools inside a running container. Applications that genuinely need to write data (logs, temp files) can mount specific tmpfs volumes for ephemeral writes. Immutable containers enforce the principle that runtime state should come only from the image and configuration, not from in-container modifications that bypass your CI/CD security pipeline.
# Run container with read-only root filesystem
docker run --read-only \
--tmpfs /tmp \
--tmpfs /var/run \
myapp:latestImage Scanning: Finding CVEs Before Deploy
Container image scanning tools analyze the packages installed in a Docker image against vulnerability databases (NVD, CVE) and report known CVEs. Leading scanners include Trivy (Aqua Security, fast and free), Grype (Anchore), Snyk Container, and AWS ECR image scanning. Scanning should be integrated into the CI/CD pipeline so that any image with critical or high CVEs fails the pipeline before being pushed to a registry. Scanners should also check for secrets (API keys, passwords) accidentally embedded in image layers.
# Scan a Docker image with Trivy
trivy image --severity HIGH,CRITICAL myapp:latest
# Fail CI pipeline if vulnerabilities found
trivy image --exit-code 1 --severity CRITICAL myapp:latestSecrets Management: Never in Image Layers
A common and dangerous mistake is embedding secrets (API keys, database passwords, TLS certificates) inside Docker images — either in environment variables baked into the image, or in files added via COPY. These secrets are visible to anyone with access to the image via docker history or by extracting image layers. Even if a subsequent layer deletes the file, it remains in the image history. Secrets should be injected at runtime via environment variables from a secrets manager, Docker secrets, or Kubernetes Secrets mounted as volumes.
# Never bake secrets into images
# Bad: ENV DATABASE_PASSWORD='supersecret'
# Good: inject at runtime via environment
docker run -e DATABASE_PASSWORD=$(vault read -field=password secret/db) myapp:latest
# Or use Docker secrets in Swarm/K8sRuntime Protection: Falco and Syscall Monitoring
Runtime security tools monitor container behavior while it is running and alert or block anomalous activity. Falco (CNCF project) hooks into the Linux kernel using eBPF or kernel modules to intercept system calls and compare them against rules. For example, a rule can alert if a container spawns a shell (execve('/bin/sh')), opens a network connection on an unexpected port, or reads /etc/shadow. These behavioral indicators often signal an active attack even if no known CVE was exploited. Sysdig Secure and Aqua Security provide commercial runtime protection platforms.
# Example Falco rule: alert on shell execution in container
# - rule: Shell Spawned in Container
# desc: A shell was spawned in a container
# condition: container and proc.name in (bash, sh, zsh)
# output: Shell spawned (user=%user.name container=%container.name)
# priority: WARNINGLinux Capabilities and Seccomp Profiles
Docker containers by default drop many Linux capabilities but still retain more than most applications need. Capabilities partition root privileges into distinct units (e.g., CAP_NET_ADMIN, CAP_SYS_ADMIN). Best practice is to drop all capabilities and add back only what is required with --cap-drop=ALL --cap-add=NET_BIND_SERVICE. Seccomp (Secure Computing Mode) profiles whitelist which system calls a container is allowed to make — Docker includes a default seccomp profile that blocks ~44 dangerous syscalls. Custom seccomp profiles for specific applications can restrict this further, blocking all syscalls the application never legitimately uses.
# Drop all capabilities, add only what's needed
docker run \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--security-opt seccomp=/etc/docker/seccomp-custom.json \
myapp:latestContainer Registries and Image Signing
Container registries (Docker Hub, AWS ECR, Google Artifact Registry) store and distribute images. Securing the registry involves: enabling vulnerability scanning on push, restricting push access to CI/CD service accounts only, enabling image signing using Sigstore/Cosign or Docker Content Trust (Notary) so that runtime environments only pull cryptographically signed images from trusted sources, and configuring image immutability so that tags cannot be overwritten (eliminating tag mutation attacks where an attacker replaces a trusted :latest tag with a malicious image).
# Sign a container image with Cosign
cosign sign --key cosign.key myregistry.io/myapp:v1.2.3
# Verify signature before deployment
cosign verify --key cosign.pub myregistry.io/myapp:v1.2.3Container Escape Techniques and Defenses
Attackers who gain code execution inside a container may attempt container escape to reach the host. Common techniques include: exploiting vulnerable privileged containers (--privileged gives nearly unrestricted host access), abusing exposed Docker sockets (/var/run/docker.sock mounted into a container gives full Docker API access including creating privileged containers), exploiting kernel vulnerabilities via unsecured capabilities. Defenses: never use privileged mode unless absolutely necessary, never mount the Docker socket into application containers, keep the host kernel patched, and use gVisor or Kata Containers for workloads requiring strong isolation.
# DANGEROUS: never do this in production
# docker run --privileged -v /:/host myapp:latest
# Check if a container is running privileged
docker inspect mycontainer | grep -i privilegedCIS Docker Benchmark Compliance
The Center for Internet Security (CIS) Docker Benchmark provides detailed security configuration guidelines for Docker hosts and containers, covering daemon configuration, image hygiene, container runtime settings, and network controls. Tools like Docker Bench for Security automate compliance checking against the CIS benchmark, producing a scored report of pass/fail items. Running this benchmark periodically and integrating it into CI/CD ensures that security configuration drift is detected quickly. Security+ candidates should know that CIS Benchmarks are a primary reference for OS and platform hardening in the exam context.
# Run Docker Bench for Security
docker run -it --net host --pid host --userns host --cap-add audit_control \
-v /var/lib:/var/lib -v /var/run/docker.sock:/var/run/docker.sock \
-v /etc:/etc docker/docker-bench-securityQuick Check
Test your understanding of CompTIA Security+ (SY0-701) concepts from this lesson.
Lesson Recap
In this lesson you learned: minimal base images and non-root users reduce the attack surface and privilege level of containerized workloads, runtime protection tools like Falco detect anomalous syscall patterns indicative of active attacks within containers, and never use privileged containers or mount the Docker socket into application containers as these configurations enable container escape. Next up we explore Kubernetes security including RBAC, network policies, and pod security standards.
Frequently asked questions
Is the “Container Security: Image Hardening and Runtime Protection” lesson free?
Yes — the full text of “Container Security: Image Hardening and Runtime Protection” is free to read here on the web, and the Cloud & IT Cert Prep course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Cloud & IT Cert Prep course, upgrade to CoddyKit PRO.
What will I learn in “Container Security: Image Hardening and Runtime Protection”?
Harden Docker images by removing unnecessary packages, running as non-root, and using runtime security tools (Falco, Sysdig) to detect anomalous container behavior. You practise Cloud & IT Cert Prep with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Cloud & IT Cert Prep?
No prior experience is required. Cloud & IT Cert Prep on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Container Security: Image Hardening and Runtime Protection” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Cloud & IT Cert Prep lesson?
Yes. Every Cloud & IT Cert Prep lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Container Security: Image Hardening and Runtime Protection
- Kubernetes Security: RBAC, Network Policies, and Pod Security
- Serverless and Function Security
- Infrastructure as Code Security Scanning