Container Security

Container security is the practice of protecting containerized applications throughout their lifecycle: from secure image construction, through registry scanning, to hardened runtime deployment on Kubernetes. It is a foundational pillar of modern DevSecOps. Source: DevOps to DevSecOps in 9 Hours

The Container Attack Surface

Containers are not inherently secure. They share the host kernel, and a compromised container with excessive privileges can escape to the host. The attack surface spans:

  • Base images: Outdated OS packages with known CVEs
  • Application layers: Vulnerable language dependencies (npm, pip, Maven)
  • Runtime configuration: Root users, writable root filesystems, excessive capabilities
  • Orchestration: Misconfigured RBAC, overly permissive NetworkPolicies, exposed registries

Image Construction Hardening

1. Minimal Base Images

Choose the smallest viable base to reduce CVE exposure:

BaseSizeUse Case
scratch~0 MBGo, Rust static binaries; zero OS attack surface
distroless~15 MBLanguage-specific minimal runtime (Java, Python, Node.js)
alpine~5 MBGeneral-purpose; uses musl libc; smaller but may have edge-case compatibility issues
debian:slim~50 MBWhen full glibc compatibility is required
ubuntu~80 MBOnly when specific Ubuntu-only tooling is needed

The Dockerize a Project page covers Dockerfile best practices including multi-stage builds that copy only runtime artifacts into the final image.

2. Non-Root Execution

Run containers as unprivileged users:

RUN addgroup -g 1001 appgroup && adduser -u 1001 -S appuser -G appgroup
USER appuser

In Kubernetes, enforce this with securityContext:

securityContext:
  runAsNonRoot: true
  runAsUser: 1001
  fsGroup: 1001

3. Read-Only Root Filesystem

Prevent runtime tampering:

securityContext:
  readOnlyRootFilesystem: true

Mount an emptyDir volume for any directories that need temporary write access (e.g., /tmp, /var/cache).

4. Drop Capabilities

Remove unnecessary Linux capabilities from the container runtime:

securityContext:
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE  # Only if binding to ports < 1024

Image Scanning

Image scanning is the process of analyzing a container image for known vulnerabilities in OS packages and application dependencies. It is the primary shift-left control for containers.

Trivy

DevOps to DevSecOps in 9 Hours uses Trivy (by Aqua Security) as the demonstration scanner. Trivy supports:

  • OS packages: Alpine, Debian, Ubuntu, RHEL, Amazon Linux
  • Application dependencies: npm, pip, Maven, Go modules
  • IaC misconfigurations: Terraform, CloudFormation, Kubernetes manifests
  • Container registries: Scan images directly from Docker Hub, ECR, GCR, ACR
# Scan a local image
trivy image myapp:1.0
 
# Scan and fail on critical vulnerabilities
trivy image --severity CRITICAL --exit-code 1 myapp:1.0
 
# Generate SARIF for GitHub Advanced Security
trivy image --format sarif --output trivy-results.sarif myapp:1.0

Pipeline Integration

A typical GitHub Actions step:

- name: Scan image with Trivy
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myapp:${{ github.sha }}'
    format: 'sarif'
    output: 'trivy-results.sarif'
- name: Upload scan results
  uses: github/codeql-action/upload-sarif@v2
  with:
    sarif_file: 'trivy-results.sarif'

Kubernetes Runtime Security

Pod Security Standards

Kubernetes 1.25+ replaced PodSecurityPolicies with Pod Security Standards (PSS), enforced via the built-in PodSecurity admission controller. Three levels exist:

LevelDescription
PrivilegedUnrestricted; intentionally dangerous. For system infrastructure only.
BaselineMinimally restrictive; prevents known privilege escalations. Default for most workloads.
RestrictedHeavily restricted; follows Pod hardening best practices. For security-critical workloads.

Enforce at the Namespace level:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

Network Segmentation

NetworkPolicies enforce zero-trust east-west traffic. A database should only accept connections from its backend tier, not from the frontend or any arbitrary Pod.

Runtime Threat Detection

Tools like Falco monitor syscalls and Kubernetes audit logs for anomalous behavior:

  • A container spawning an unexpected shell (bash, sh)
  • A Pod making an outbound connection to a rare IP
  • A privileged container being created in a production namespace

The Defense-in-Depth Stack

LayerControlTool / Pattern
ImageMinimal base, non-root, read-only FSDockerfile best practices
RegistryVulnerability scan before pushTrivy, Snyk Container
BuildFail on critical CVEsCI/CD quality gates
DeploySigned images, admission controlCosign, Kyverno, OPA Gatekeeper
RuntimeNetwork segmentation, resource limitsNetworkPolicies, LimitRanges
DetectAnomaly detection, audit loggingFalco, Prometheus + Alertmanager

See Also


Tags: container-security docker kubernetes trivy devsecops pod-security image-scanning