Container and Kubernetes threat model
Container security has multiple distinct attack surfaces, each requiring different scanning approaches:
- Base image vulnerabilities: CVEs in OS packages, language runtimes, and libraries included in the container image.
- Kubernetes misconfigurations: Overly permissive pod security contexts, excessive RBAC permissions, missing network policies, exposed dashboards.
- Supply chain compromise: Malicious or tampered base images, compromised container registries, unsigned images.
- Runtime threats: Container breakout attempts, privilege escalation, lateral movement, cryptomining in pods.
- Secrets in images or manifests: API keys or credentials embedded in Dockerfiles, environment variables in YAML, or baked into image layers.
Shift left and right: Container security requires both pre-deployment scanning (shift left β catch issues before they reach production) and runtime monitoring (shift right β detect threats in running environments). Neither alone is sufficient.
Container image scanning
Image scanning analyses container images for known CVEs in OS packages and application dependencies. It should run at every point where an image is built or pulled.
When to scan
- At build time (CI): Scan the image immediately after it is built. Fail the pipeline on critical/high CVEs.
- At push time: Scan again when pushing to the registry. Some registries (ECR, GCR, Docker Hub) offer built-in scanning on push.
- Continuously in the registry: New CVEs are disclosed daily. An image that was clean last week may be vulnerable today. Schedule periodic rescans of images in the registry.
- At deployment time: Admission controllers (OPA Gatekeeper, Kyverno) can block deployment of images that fail scanning policy.
# Scan a container image trivy image --severity HIGH,CRITICAL myapp:latest # Scan and output SARIF for GitHub Security tab trivy image --format sarif --output results.sarif myapp:latest # Fail CI if critical CVEs found trivy image --exit-code 1 --severity CRITICAL myapp:latest # Scan a Dockerfile for misconfigurations too trivy config Dockerfile
Distroless and minimal base images
Reducing the image footprint reduces the attack surface. Distroless images contain only the application and its runtime dependencies β no shell, no package manager, no unnecessary utilities. This dramatically reduces the number of CVEs in the base image and limits what an attacker can do after a container compromise.
Kubernetes manifest scanning
Kubernetes YAML manifests define how containers run β and many default configurations are insecure. Manifest scanning analyses deployment, pod, and other resource definitions for security misconfigurations before they reach the cluster.
Common Kubernetes misconfigurations
runAsRoot: trueor norunAsNonRootconstraint β containers running as root- Missing
readOnlyRootFilesystem: trueβ writable root filesystem enables persistence privileged: trueβ effectively gives the container host access- Missing resource limits β enables CPU/memory DoS
hostNetwork: true,hostPID: true,hostIPC: trueβ breaks container isolation- Missing network policies β all pods can communicate by default
- Missing
seccompProfileβ no syscall filtering - Secrets mounted as environment variables instead of volume mounts
apiVersion: apps/v1 kind: Deployment spec: template: spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: app securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] resources: limits: cpu: "500m" memory: "128Mi"
Pod Security Standards (PSS)
Kubernetes 1.25+ ships with built-in Pod Security Admission, replacing the deprecated PodSecurityPolicy. Three security levels are defined:
- Privileged: Unrestricted β allows known privilege escalation paths. Only for trusted system workloads.
- Baseline: Minimally restrictive β prevents known privilege escalations while allowing typical containerised workloads. Good starting point.
- Restricted: Follows current pod hardening best practices. Requires non-root execution, read-only root filesystem, capability dropping. Target for production workloads.
# Label a namespace to enforce restricted PSS
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restrictedRBAC hardening
Kubernetes RBAC misconfigurations are a primary path for privilege escalation. Common issues:
- Overly permissive ClusterRoles with
*verbs or resources - Binding ServiceAccounts to
cluster-admin - Default ServiceAccount tokens automounted in pods that do not need API access
- Permissions to
createpods,execinto pods, orescalateroles β all allow privilege escalation
apiVersion: v1 kind: ServiceAccount metadata: name: my-app # Disable token automounting for SAs that don't need API access automountServiceAccountToken: false
Runtime threat detection
Static scanning catches known vulnerabilities and misconfigurations before deployment. Runtime detection catches anomalous behaviour in running containers β zero-days, misconfigured allowlists, insider threats, and post-exploitation activity.
- Falco: The leading open-source runtime security tool for Kubernetes. Uses eBPF or kernel module to monitor syscalls and detect anomalous behaviour β shell spawned in a container, file written to sensitive path, network connection to unexpected destination.
- Tetragon (Cilium): eBPF-based security and observability. Provides process-level visibility with fine-grained policy enforcement at the kernel level.
- Cloud provider solutions: AWS GuardDuty EKS Protection, GCP Security Command Center, Azure Defender for Containers all provide managed runtime detection with deep cloud integration.
CI/CD integration
name: Container Security Scan on: [push, pull_request] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build image run: docker build -t myapp:${{ github.sha }} . - name: Scan image with Trivy uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} severity: CRITICAL,HIGH exit-code: '1' - name: Scan Kubernetes manifests uses: aquasecurity/trivy-action@master with: scan-type: config scan-ref: k8s/ exit-code: '1'
Tool comparison
Tool What it scans Type ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ Trivy Images, manifests, Dockerfiles OSS, multi-purpose Checkov Kubernetes YAML, Helm, Terraform OSS, IaC focus kube-bench Cluster CIS benchmark OSS, node/cluster kube-hunter Penetration testing OSS, active testing Falco Runtime syscall behaviour OSS, runtime Kubescape Manifests + framework mapping OSS, MITRE ATT&CK AquilaX IaC Manifests, Helm, Terraform, Docker Enterprise, CI/CD
Layered approach: Use Trivy or AquilaX for image and manifest scanning in CI, kube-bench to audit cluster configuration periodically, and Falco for runtime detection. Different tools catch different things β the layers complement each other.
Scan Kubernetes manifests and container images
AquilaX IaC scanning analyses Kubernetes YAML, Helm charts, and Dockerfiles for misconfigurations β integrated into your CI/CD pipeline in minutes.
Scan your Kubernetes configs β