Container Security Scanning: What to Test in Docker and Kubernetes Deployments
Most teams deploying to containers assume that because everything is "in a container," they're somehow more secure. Containers do provide meaningful isolation — but they introduce an entirely new attack surface that traditional security scanning doesn't cover.
If you're running Docker containers on Kubernetes and your security scanning only tests the running web application, you're missing significant risk exposure. This guide covers what actually needs scanning in a containerized environment, what tools cover each layer, and how web application scanning (DAST) fits into the overall picture.
The Container Security Stack
Container security involves at least four distinct layers, each with its own threat model:
| Layer | What Lives Here | Primary Threats |
|---|---|---|
| Image / Build | Base image, OS packages, app dependencies | Vulnerable packages, hardcoded secrets, excessive permissions |
| Runtime / Container | Running container configuration | Privileged containers, exposed ports, mounted host paths |
| Orchestration | Kubernetes RBAC, network policies, cluster config | Overprivileged service accounts, missing network policies, exposed API server |
| Application | The running web application / API | OWASP Top 10, injection flaws, auth issues, business logic |
Each layer requires different tooling. No single scanner covers all four.
Layer 1: Docker Image Scanning
Image scanning is the most accessible starting point because it doesn't require a running cluster — you can scan images in CI/CD before they're deployed.
What to look for
OS package vulnerabilities: Your base image (e.g., debian:12, ubuntu:22.04, python:3.12-slim) ships with operating system packages. These packages accumulate CVEs over time. Image scanners match installed packages against the NVD and OS-specific vulnerability databases (Debian Security Tracker, Ubuntu CVE Tracker, Red Hat CVE database, etc.).
Application dependency vulnerabilities: Your requirements.txt, package.json, go.mod, or Gemfile.lock dependencies get baked into the image. Image scanners check these against the same CVE databases.
Hardcoded secrets: Developers sometimes accidentally bake secrets into image layers — API keys in environment variables, credentials in config files, private keys in the build context. Secret scanning at the image layer catches these before deployment.
Dockerfile misconfigurations: Running as root, exposing unnecessary ports, missing USER directive, installing debug tools in production images. Static analysis of your Dockerfile catches these before they become runtime issues.
Tools
- Trivy — open source, scans images, filesystems, git repos. Checks OS packages, language dependencies, and misconfiguration. Fast, accurate, and easy to integrate into CI/CD.
- Grype — open source from Anchore. Strong vulnerability matching, good false positive rate, integrates with SBOM generation tools.
- Snyk Container — commercial, tight IDE and CI/CD integration, strong fix guidance. Good for teams that want managed tooling.
- Hadolint — Dockerfile linter specifically. Not a CVE scanner but catches common Dockerfile security anti-patterns.
CI/CD integration
Scan on every image build, before push to registry. Block on Critical findings; create tickets for High and Medium. Example with Trivy in GitHub Actions:
- name: Scan container image
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
exit-code: '1'
severity: 'CRITICAL'
Base image hygiene: Use minimal base images (distroless, alpine, language-specific slim variants). Fewer packages = smaller attack surface = fewer CVEs to manage. Rebuild images regularly to pick up patched base image versions.
Layer 2: Runtime Container Configuration
Even a clean image can be deployed insecurely. Runtime configuration scanning checks how containers are actually running, not just what's in them.
High-risk runtime configurations
Privileged containers: Running with --privileged or privileged: true in your Kubernetes pod spec gives the container near-root access to the host kernel. This is one of the most dangerous misconfigurations — a container escape becomes a full host compromise. Legitimate use cases are rare (low-level system tools); flag all others.
Running as root: Containers running as UID 0 make privilege escalation easier if the application is compromised. Add USER nonroot (or a specific non-root UID) to your Dockerfile and set runAsNonRoot: true in your pod security context.
Exposed ports: Containers that expose ports beyond what the application needs increase attack surface. Map out what each container needs to expose and lock down port configuration in your compose files and Kubernetes service definitions.
Writable root filesystem: A writable root filesystem allows an attacker to modify the container after initial compromise. Set readOnlyRootFilesystem: true in your security context and mount only the directories that legitimately need write access.
Capabilities: Linux capabilities can be granted individually rather than via the blunt --privileged flag. Many containers run with more capabilities than they need. Drop all capabilities and only add the specific ones required: drop: [ALL], add: [NET_BIND_SERVICE].
Layer 3: Kubernetes Configuration
Kubernetes introduces an entirely new class of security configuration that doesn't exist in non-containerized deployments.
RBAC: Role-Based Access Control
Kubernetes RBAC controls what principals (users, service accounts) can do. Common problems:
- Overly permissive ClusterRoles — granting
cluster-adminor wildcard permissions to service accounts that don't need them - Default service account misuse — pods that use the default service account (which often has no RBAC restrictions) can access the Kubernetes API
- Wildcard verbs or resources —
verbs: ["*"]on sensitive resources like secrets
Network Policies
By default, Kubernetes allows all pods to communicate with all other pods in the cluster. Without explicit NetworkPolicy resources, a compromised pod can reach any other pod — internal APIs, databases, control plane services.
Implement a deny-all default policy for each namespace and add explicit allow rules for required communication paths:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Secrets Management
Kubernetes Secrets are base64-encoded, not encrypted. By default, they're stored in plaintext in etcd. Common problems:
- Secrets mounted as environment variables (visible in process lists, crash dumps, logs)
- Overly broad RBAC that allows reading all secrets in a namespace
- etcd not encrypted at rest
- Secrets committed to version control (use Sealed Secrets, External Secrets Operator, or Vault)
Tools for Kubernetes scanning
- kube-bench — CIS Kubernetes Benchmark checks. Open source, runs against your cluster to check compliance with security best practices.
- Trivy — also scans Kubernetes manifests and running cluster configurations for misconfigurations (supports
trivy k8s). - Polaris — validates Kubernetes workloads against security and best-practice policies. Open source, with Helm chart for cluster-wide deployment.
- KubeAudit — audits Kubernetes clusters against security best practices. Good for RBAC analysis.
- Checkov — static analysis for IaC including Kubernetes YAML, Terraform, Dockerfiles. Catches misconfigurations at the manifest level before deployment.
Layer 4: Application Security (DAST)
DAST testing — testing the running application from the outside, as an attacker would — is independent of containers. It doesn't care whether your application is running in Docker, Kubernetes, a VM, or bare metal. It tests HTTP behavior.
What DAST covers in a containerized application is identical to what it covers anywhere else:
- OWASP Top 10 vulnerabilities in the application layer (injection, authentication, access control)
- TLS/SSL configuration
- Security header configuration (CSP, HSTS, X-Frame-Options)
- Known CVEs in identified web technologies
- API security issues (authentication bypass, IDOR, mass assignment)
What DAST does not cover: image vulnerabilities, container runtime misconfigurations, Kubernetes RBAC, secrets management. These are infrastructure and orchestration concerns, not application concerns.
Key insight: In a containerized deployment, your security scanning needs to span all four layers. DAST handles the application layer. Image scanning handles the OS and dependency layer. Runtime and orchestration scanning handles the container and Kubernetes layer. None of these is a substitute for the others.
Building a Container Security Pipeline
Here's how a mature containerized environment structures security scanning across the development lifecycle:
Development (shift left)
- IDE plugins for secret detection (GitLeaks, detect-secrets)
- Pre-commit hooks for Dockerfile linting (Hadolint)
- Dependency scanning in the IDE
CI/CD pipeline
- SCA: dependency vulnerability scanning on every PR (Trivy, Snyk, Grype)
- SAST: static analysis for code-level vulnerabilities
- Image scanning: on every built image before push (Trivy, Grype)
- IaC scanning: Kubernetes YAML, Dockerfile, Terraform (Checkov, Trivy)
- Block merges on Critical; create tickets for High
Pre-deployment / staging
- DAST: automated web application testing against deployed staging environment
- Kubernetes benchmark: kube-bench against staging cluster
Production (continuous)
- Runtime security monitoring (Falco for container behavior)
- Scheduled DAST against production
- Registry scanning for newly discovered CVEs in deployed images
Where to Start If You're Starting from Zero
If you're containerized and have no security scanning in place, here's the prioritized starting point:
- Add Trivy to CI/CD — block on Criticals, alert on High. This takes under a day and immediately catches the most dangerous known vulnerabilities in your images and dependencies.
- Run kube-bench — get a snapshot of your cluster's security posture against CIS benchmarks. One-time run, produces a prioritized remediation list.
- Implement default-deny NetworkPolicies — the biggest impact Kubernetes security control, often missed. Limits lateral movement.
- Audit RBAC — look for ClusterAdmin bindings, wildcard permissions, and service accounts that don't need cluster access. Clean these up before anything else in RBAC.
- Start DAST — once infrastructure scanning is running, add automated web application scanning against your staging environment on a weekly schedule.
You don't need to do everything at once. Each of these can be implemented independently, and each produces immediate value. Build the pipeline incrementally rather than waiting to implement everything perfectly before starting.
Ironimo provides the DAST layer for containerized applications — the same Kali Linux tools your security team would run manually, automated on a schedule. Test your web application security independent of whether you're on Docker, Kubernetes, or bare metal.
Start free scan