Container Security
Container image scanning, runtime hardening, and security best practices for production workloads
You are an expert in container security for containerized application development and deployment. ## Key Points - name: tmp - name: tmp - name: db-creds - name: app - Pin image digests in production (`image: myapp@sha256:abc123...`) to prevent tag mutation attacks. - Drop all Linux capabilities and add back only the specific ones required, if any. - Run vulnerability scans on every CI build and block deployments that introduce CRITICAL-severity CVEs. - Scanning images only at build time but not re-scanning images already in production; new CVEs are published daily against existing packages. - Using `latest` tags in production, which makes it impossible to audit exactly which code is running and can silently introduce vulnerable or untested changes.
skilldb get containerization-skills/Container SecurityFull skill: 201 linesContainer Security — Containerization
You are an expert in container security for containerized application development and deployment.
Overview
Container security spans the full lifecycle: building trusted images, scanning for vulnerabilities, enforcing least-privilege at runtime, and monitoring workloads in production. A defense-in-depth approach applies controls at the image, container, orchestrator, and host layers.
Core Concepts
Image Scanning
Scan images for known CVEs in OS packages and application dependencies before they reach production:
# Trivy — scan a local image
trivy image myapp/web:1.4.0
# Scan with severity filter and exit code for CI gating
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp/web:1.4.0
# Grype — alternative scanner
grype myapp/web:1.4.0
# Scan a Dockerfile for misconfigurations
trivy config --policy-bundle-repository ghcr.io/aquasecurity/trivy-policies ./Dockerfile
Non-Root Containers
Never run containers as root. Create a dedicated user in the Dockerfile:
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]
Read-Only Filesystems
Prevent runtime tampering by making the root filesystem read-only:
# Kubernetes SecurityContext
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
Provide writable volumes only where needed:
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Secrets Management
Never embed secrets in images. Use orchestrator-native secrets or external vaults:
# Kubernetes Secret mounted as volume
volumes:
- name: db-creds
secret:
secretName: db-credentials
containers:
- name: app
volumeMounts:
- name: db-creds
mountPath: /etc/secrets
readOnly: true
Implementation Patterns
CI Pipeline Scanning
# GitHub Actions example
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1
- name: Upload results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-results.sarif
Pod Security Standards
Enforce security baselines at the namespace level using Pod Security Admission:
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
Network Policies
Restrict pod-to-pod communication to only what is necessary:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- port: 5432
Best Practices
- Pin image digests in production (
image: myapp@sha256:abc123...) to prevent tag mutation attacks. - Drop all Linux capabilities and add back only the specific ones required, if any.
- Run vulnerability scans on every CI build and block deployments that introduce CRITICAL-severity CVEs.
Core Philosophy
Container security is a layered discipline that starts at the image and extends through the runtime, the orchestrator, and the host. No single control is sufficient; the goal is defense in depth where each layer compensates for weaknesses in the others. A vulnerability in a base image is mitigated by a non-root runtime user, which is backstopped by a read-only filesystem, which is further constrained by network policies limiting lateral movement.
The principle of least privilege applies at every layer. Containers should run as non-root users with dropped capabilities. Pods should have read-only root filesystems. Network policies should default-deny and explicitly allow only required communication paths. Secrets should be mounted read-only from external stores rather than baked into images or passed as environment variables. Each restriction narrows the blast radius of a compromise.
Security is a continuous process, not a one-time gate. Scanning an image at build time catches the vulnerabilities known today, but new CVEs are published daily against packages already in production. Continuous scanning of running images, combined with automated alerting and a clear remediation workflow, ensures that your security posture does not degrade over time. The goal is not zero vulnerabilities (which is often impossible) but a bounded, understood, and actively managed risk surface.
Anti-Patterns
-
Running containers as root by default. Many base images default to running as root. Without an explicit
USERdirective in the Dockerfile andrunAsNonRoot: truein the pod security context, a container escape gives the attacker root access on the host. Always create and switch to a non-root user. -
Allowing all network traffic between pods. Without network policies, every pod can communicate with every other pod in the cluster. A compromised web frontend can directly reach the database, the secret store, and every internal service. Apply default-deny network policies and explicitly allow only required paths.
-
Baking secrets into container images. Embedding API keys, database passwords, or TLS certificates in the Dockerfile or image layers makes them accessible to anyone who can pull the image. Use Kubernetes Secrets, external vault integrations, or mounted secret volumes instead.
-
Ignoring image provenance and signing. Pulling unsigned images from public registries without verifying their provenance means trusting that no one has tampered with the image between the author's build and your deployment. Use image signing (cosign, Notary) and admission controllers that enforce signature verification.
-
Using
privileged: trueto work around permission issues. Granting privileged mode gives the container nearly unrestricted host access and defeats every other security control. Diagnose the actual permission needed and grant only that specific capability.
Common Pitfalls
- Scanning images only at build time but not re-scanning images already in production; new CVEs are published daily against existing packages.
- Using
latesttags in production, which makes it impossible to audit exactly which code is running and can silently introduce vulnerable or untested changes.
Install this skill directly: skilldb add containerization-skills
Related Skills
Container Registries
Container registry setup, authentication, and image management for ECR, GCR, GHCR, and Docker Hub
Docker Compose
Docker Compose configuration for multi-service development, testing, and local orchestration
Docker Networking
Docker networking modes, custom networks, DNS resolution, and multi-host connectivity patterns
Dockerfile Optimization
Multi-stage builds, layer caching, and image size optimization for production Docker images
Helm Charts
Helm chart creation, templating, dependency management, and release lifecycle for Kubernetes
Kubernetes Autoscaling
Kubernetes autoscaling with HPA, VPA, Cluster Autoscaler, and event-driven scaling with KEDA