Containers have transformed how we deploy applications, but they also introduce new security challenges. From vulnerable base images to privileged containers, understanding container security is critical.
In this guide, we’ll explore container security at every layer: images, registries, and runtime.
The Container Attack Surface
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Container Security Layers โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Runtime Security โ โ
โ โ - Container isolation โ โ
โ โ - Resource limits โ โ
โ โ - Runtime protection โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Registry Security โ โ
โ โ - Access control โ โ
โ โ - Image signing โ โ
โ โ - Vulnerability scanning โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Image Security โ โ
โ โ - Minimal base images โ โ
โ โ - No secrets in images โ โ
โ โ - Regular updates โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ Build Security โ โ
โ โ - SBOM generation โ โ
โ โ - Supply chain security โ โ
โ โ - CI/CD pipeline security โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Image Security
Secure Image Building
# BAD: Large base image with secrets
FROM ubuntu:latest
RUN apt-get update && apt-get install -y python
COPY . /app
ENV API_KEY=secret123 # NEVER DO THIS!
# GOOD: Minimal image, no secrets
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nonroot:nonroot
Image Best Practices
# Multi-stage build for smaller images
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
USER node
# Never run as root!
USER nonroot:nonroot
# Use specific versions, not :latest
FROM python:3.12.2-slim
# Scan for vulnerabilities in build
# RUN /usr/local/bin/trivy image myapp:latest
Secret Management
# BAD: Secrets in image
# docker-compose.yml
services:
app:
image: myapp
environment:
- DATABASE_PASSWORD=secret # NEVER!
# GOOD: Use secrets management
services:
app:
image: myapp
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt # Or external secrets manager
# Kubernetes secrets
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: admin
password: ${DB_PASSWORD} # Injected from vault
Registry Security
Private Registry Security
# Registry access control
authentication:
# Use strong authentication
- Type: "OIDC or LDAP"
Provider: "Keycloak or Okta"
# Enable anonymous access only for public images
anonymous_access: false
scanning:
# Scan on push
on_push: true
# Block vulnerable images
fail_on_severity: "HIGH"
# Scan schedule for existing images
periodic_scan: "daily"
Image Signing
# Sign images with Cosign (Sigstore)
# Install Cosign
brew install cosign
# Generate key pair
cosign generate-key-pair
# Sign image
cosign sign myregistry.io/myapp:latest
# Verify signature
cosign verify myregistry.io/myapp:latest
# Store in registry transparency log
cosign store myregistry.io/myapp:latest
Vulnerability Scanning
# Using Trivy
# Scan image
trivy image myapp:latest
# Scan with severity filter
trivy image --severity HIGH,CRITICAL myapp:latest
# Scan in CI/CD
trivy image \
--exit-code 1 \
--severity CRITICAL \
--ignore-unfixed \
myapp:latest
# Scan Dockerfile for best practices
trivy config my-dockerfile/
# Generate SBOM
trivy sbom myapp:latest --format spdx
Runtime Security
Container Runtime Protection
# Docker security options
# Run as non-root
securityContext:
runAsNonRoot: true
runAsUser: 10000
runAsGroup: 10000
fsGroup: 10000
# Drop all capabilities, add only what's needed
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
# Read-only root filesystem
securityContext:
readOnlyRootFilesystem: true
# Prevent privilege escalation
securityContext:
allowPrivilegeEscalation: false
Kubernetes Security Context
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10000
fsGroup: 10000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
limits:
memory: "128Mi"
cpu: "500m"
requests:
memory: "64Mi"
cpu: "250m"
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
Network Policies
# Kubernetes Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-app-to-db
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: app
ports:
- protocol: TCP
port: 5432
Resource Limits
# Resource quotas and limits
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
spec:
hard:
requests.cpu: "4"
limits.cpu: "8"
requests.memory: 8Gi
limits.memory: 16Gi
pods: "20"
---
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
spec:
limits:
- default:
memory: "256Mi"
cpu: "250m"
defaultRequest:
memory: "128Mi"
cpu: "100m"
type: Container
Supply Chain Security
SBOM (Software Bill of Materials)
# Generate SBOM
# Using Syft
syft myapp:latest -o json > sbom.json
syft myapp:latest -o spdx > sbom.spdx
# Using Trivy
trivy sbom myapp:latest --format spdx-json > sbom.json
# Verify against known vulnerabilities
syft myapp:latest | grype
Supply Chain Security Tools
# SLSA (Supply-chain Levels for Software Artifacts)
slsa_levels = {
"level_1": {
"description": "Documentation",
"requirements": "Build process is documented"
},
"level_2": {
"description": "Hosted build",
"requirements": "Build runs on hosted service"
},
"level_3": {
"description": "Generated",
"requirements": "Build system generates provenance"
},
"level_4": {
"description": "Hardened",
"requirements": "Build is reproducible, auditable"
}
}
# Tools to achieve SLSA:
# - Cosign: Image signing
# - Tekton: Secure build pipelines
# - Sigstore: Open source signing
# - SBOM generators: Syft, Trivy
Security Scanning in CI/CD
# GitHub Actions - Container security
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
- name: Run Cosign sign
uses: sigstore/cosign-installer@main
with:
cosign-version: 'v2.0.0'
run: |
cosign sign --yes myregistry.io/myapp:${{ github.sha }}
Runtime Protection
Falco - Runtime Security
# Falco rules
rules:
- rule: "Detect shell in container"
desc: "A shell was spawned in a container"
condition: >
evt.type = execve and
evt.arg[0] = /bin/sh
output: "Shell spawned in container (user=%user.name command=%proc.cmdline container_id=%container.id)"
priority: WARNING
- rule: "Detect privileged container"
desc: "Privileged container detected"
condition: >
container.privileged = true
output: "Privileged container (command=%proc.cmdline image=%container.image.repository)"
priority: CRITICAL
- rule: "Sensitive file access"
desc: "Access to sensitive files"
condition: >
fd.name in (/etc/shadow, /etc/passwd)
and container.id != host
output: "Sensitive file access (file=%fd.name user=%user.name)"
priority: WARNING
Seccomp and AppArmor
# Seccomp profile (Kubernetes)
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
seccompProfile:
type: Localhost
localhostProfile: profiles/myprofile.json
# AppArmor profile
/etc/apparmor.d/usr.sbin.myapp
Conclusion
Container security requires defense in depth:
- Images: Minimal base, no secrets, frequent updates
- Registry: Access control, signing, scanning
- Runtime: Security contexts, network policies, limits
- Supply chain: SBOM, SLSA, signing
Automate security scanning in CI/CD and enforce policies in production.
Comments