☁️ Cloud Security July 27, 2026 · 15 min read

Container Security Audit Checklist: 50 Checks That Matter

Pragmatic 50-point container security audit checklist — build, registry, runtime, RBAC, network, detection. What attackers exploit and the fixes.

CS
☁️ Cloud Security
CS

Container security audits get done at one of two depths. The shallow version scans images for CVEs, reports a four-digit count of “vulnerabilities,” and produces a finding list nobody reads. The deep version inspects the actual blast radius of a compromised container — who can the workload assume, what data can it reach, what does the cluster’s RBAC actually permit, and which detection signal would fire if any of it went wrong. The shallow version satisfies compliance; the deep version closes incidents. After running container audits as part of Kubernetes and container security engagements across many environments, a consistent picture emerges: the security-relevant findings concentrate in a few well-known categories, and a focused 50-check audit catches more than 95% of the real risk. This is the field-tested checklist — what to inspect, why it matters, what attackers exploit when each check fails, and how to sequence the fixes.

Why most container audits stop at CVE scanning

CVE scanning produces output. Output produces compliance documentation. Compliance documentation closes audit cycles. The combination has trained the industry to optimise for finding count rather than blast-radius reduction.

What CVE scanning actually tells you

A CVE scan tells you “this package version has a known vulnerability.” It does not tell you whether the vulnerable code path is reachable, whether the container has the privilege to do anything dangerous when the vulnerability is exploited, or whether your detection stack would catch the exploitation if it happened. Three containers with the same CVE list can have radically different real-world risk profiles depending on these three questions.

What container audits actually need to cover

The full picture requires inspecting eight layers, each with its own attack patterns:

  1. Image build pipeline — what gets into the image and how is it verified
  2. Registry and supply chain — who can push, who can pull, what is verified
  3. Runtime configuration — privileges, capabilities, resources, mounts
  4. Cluster security — control plane hardening, etcd, API server
  5. Identity, RBAC, and secrets — who can do what, how secrets are exposed
  6. Network policy — what can talk to what
  7. Observability and detection — would you see an attack
  8. Incident response readiness — could you respond to one

The 50 checks below distribute across these layers in roughly the proportions that matter — runtime config and RBAC dominate, build pipeline and registry follow, network and detection round it out.

How to use this checklist

Each check below has three components: what to verify, what attacker exploits when the check fails, and the specific remediation. The recommended audit sequence:

  1. Phase 1 (Day 1-3): checks marked Critical. Run through these against every cluster in scope. Document findings.
  2. Phase 2 (Week 1-2): checks marked High. Surface the patterns that show up across multiple workloads.
  3. Phase 3 (Week 2-4): checks marked Medium. Use these to build the longer-term hardening backlog.
  4. Phase 4 (Month 2): continuous controls that prevent recurrence.

Score each check as Pass, Fail, or N/A per workload/cluster. Aggregate to a heat map. Fix highest-blast-radius failures first.

Image build pipeline (Checks 1-10)

This is where supply-chain attacks land. Most production breaches involving containers begin with a malicious or vulnerable image entering the registry through a permissive build pipeline.

#CheckSeverityWhat attackers exploit when this fails
1Base images pinned by digest, not tag (@sha256:... not :latest)HighImage pull-time substitution; supply-chain compromise via tag re-pointing
2Base images from a curated approved list, not arbitrary registriesHighMalicious image upload to public registries; typosquatting
3Multi-stage builds used to strip build dependencies from final imageMediumLarger attack surface; build tools available at runtime
4No secrets in image layers (verified via layer inspection, not source)CriticalCredential extraction from leaked images; old layer secret recovery
5No interactive credentials in build argsHighCI log leak; build cache leak
6Dockerfile uses non-root USER directiveHighPrivilege escalation if container is compromised
7Image signed via cosign / Notation / SigstoreHighImage tampering between registry and cluster
8SBOM generated and attached to imageMediumInability to respond to disclosed CVEs without manual inventory
9Image scan integrated into CI with severity gateHighVulnerable images shipped to production
10Build pipeline runs in isolated environment (not on developer machines)MediumBuild-host compromise contaminates production images

The single highest-leverage check in this category is #4 — secrets in image layers. Even when a developer removes a secret in a later layer, the secret remains in the earlier layer and can be extracted by anyone with image pull access. Common offenders: API keys baked into early COPY directives, SSH keys used during build, npm/pip credentials.

Verification command for the most common secret patterns:

docker save image:tag | tar -xO --wildcards '*/layer.tar' | \
  tar -tO 2>/dev/null | grep -aE '(AWS|API_KEY|SECRET|PASSWORD|BEGIN.*PRIVATE)'

For CI integration of image signing and SBOM, cosign + syft is the current de facto stack:

syft my-registry/my-app:1.2.3 -o spdx-json > sbom.json
cosign sign --key cosign.key my-registry/my-app:1.2.3
cosign attest --predicate sbom.json --key cosign.key my-registry/my-app:1.2.3

Registry and supply chain (Checks 11-16)

The registry is the bridge between build and runtime. A compromised registry, or a registry with weak access control, defeats the security model that depends on trusting the images it serves.

#CheckSeverityWhat attackers exploit when this fails
11Registry requires authentication for both push and pullCriticalAnonymous image upload; supply-chain injection
12Push credentials issued per-pipeline, not sharedHighCredential leak from one pipeline compromises all
13Image pull policy enforced via admission controller (only signed images)CriticalUnsigned or unauthorised images deployed
14Vulnerability rescanning enabled on new CVE disclosuresHighLong-running images with newly-disclosed CVEs invisible
15Image retention policy in place, old images removedLowForgotten old images with credentials or vulnerabilities
16Cross-region replication keys rotated and access-loggedMediumReplication compromise; stale credential abuse

Check #13 is the most underutilised registry control. Admission controllers like Kyverno or OPA Gatekeeper can enforce “only deploy images signed by our cosign key” — preventing both supply-chain attacks and accidental deployment of unintended images.

# Kyverno policy: require cosign-signed images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-signed-images
spec:
  validationFailureAction: enforce
  rules:
    - name: verify-signature
      match:
        resources:
          kinds: [Pod]
      verifyImages:
        - imageReferences: ["my-registry/*"]
          attestors:
            - entries:
                - keys:
                    publicKeys: |
                      -----BEGIN PUBLIC KEY-----
                      <cosign public key>
                      -----END PUBLIC KEY-----

Runtime configuration (Checks 17-26)

Runtime configuration determines what a compromised container can actually do. This is the densest category in the audit because the failures here turn small vulnerabilities into large incidents.

#CheckSeverityWhat attackers exploit when this fails
17privileged: false on all production podsCriticalDirect host compromise from container escape
18runAsNonRoot: true enforced via Pod Security AdmissionHighContainer processes running as root; easier privilege escalation
19allowPrivilegeEscalation: false on all production podsHighSetuid binary escalation inside container
20readOnlyRootFilesystem: true where workload supports itMediumFilesystem-based persistence; binary modification
21Linux capabilities dropped to least required (drop ALL, add specific)HighCapability abuse for network/filesystem operations
22No mount of host paths (hostPath), or restricted to approved listCriticalHost filesystem read/write from container
23No hostNetwork, hostPID, hostIPC on production podsCriticalCluster-wide visibility from a single pod
24Resource limits (CPU/memory) set on every containerMediumDoS; noisy-neighbour; OOM-kill cascade
25Liveness and readiness probes do not expose sensitive endpointsLowInformation disclosure via probe responses
26Pod Security Admission set to restricted or equivalent enforcementHighWorkloads can opt out of all the above with no central enforcement

Pod Security Admission (PSA) is the central enforcer for most of this category. The restricted profile enforces #17, #18, #19, #20, #21, parts of #22, and #23 — but only if the namespace label is set. Audit every namespace for the PSA label:

kubectl get namespaces -L pod-security.kubernetes.io/enforce,pod-security.kubernetes.io/audit,pod-security.kubernetes.io/warn

Any production namespace without enforce=restricted (or baseline with documented justification) fails check #26.

For deeper context on the hardening config that backs these checks, see our Kubernetes security hardening for containers post.

Cluster security (Checks 27-36)

The cluster control plane is the highest-blast-radius surface. A compromise of the API server, etcd, or kubelet typically means cluster takeover.

#CheckSeverityWhat attackers exploit when this fails
27API server bound to private network or restricted CIDRCriticalInternet-exposed API server; brute-force kubeconfig recovery
28API server audit logging enabled with appropriate policyHighLack of forensic evidence; missed detection signal
29etcd encryption at rest enabled with KMS-backed keyCriticalSecret extraction from etcd snapshots
30etcd access restricted to control plane nodes onlyCriticalDirect etcd read/write bypasses API authorisation
31Kubelet authentication/authorisation set to webhook modeCriticalAnonymous kubelet API access; pod exec from outside
32Kubelet port not exposed beyond nodeHighLateral movement via kubelet API
33Control plane TLS certificates rotated automaticallyMediumStale certificates; manual rotation drift
34Anonymous auth disabled on API serverHighProbing API surface without credentials
35API server TLS uses strong cipher suite, no TLS < 1.2MediumDowngrade attacks; protocol-level weaknesses
36CIS Kubernetes Benchmark compliance scan run and remediatedMediumSystematic miss of well-known weak settings

For managed Kubernetes (EKS, GKE, AKS), checks #29, #30, #31, #33, #34 are partially handled by the cloud provider — but only partially. Each provider has knobs the customer owns. EKS, for example, requires the customer to explicitly enable secrets encryption with KMS; the default cluster has no envelope encryption.

CIS Benchmark scanning is fastest via kube-bench:

kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench

Identity, RBAC, and secrets (Checks 37-44)

The container’s identity surface — service accounts, RBAC roles, secrets — is what determines blast radius. Most container compromises become cluster compromises through identity misconfiguration. The patterns mirror the broader cloud identity problems documented in our AWS IAM audit walkthrough.

#CheckSeverityWhat attackers exploit when this fails
37Default service account has no RBAC permissionsCriticalPods using default SA have unintended cluster access
38Service account tokens not automounted unless explicitly neededHighPod-to-API-server access from compromised workloads
39ClusterRoleBindings to cluster-admin audited and minimisedCriticalService account compromise = cluster admin
40Service account-to-IAM mapping (IRSA/Workload Identity) scoped to least privilegeCriticalPod-to-cloud-account lateral movement
41Secrets stored in dedicated secret store (Vault/Secrets Manager), not as plain k8s secretsHighPlain k8s secrets are base64-encoded, not encrypted, easily exfiltrated
42Secrets injected via projected volumes or external secrets operatorHighSecrets in environment variables are visible in process listings and crash dumps
43Image pull secrets per-namespace, not cluster-wideMediumCompromise of one workload exposes pull credentials for all images
44Service account audit log review quarterlyMediumStale or unused service accounts retain dangerous permissions

Check #40 is the highest-leverage cross-system control. A pod’s service account often maps to a cloud IAM role (via IRSA on EKS, Workload Identity on GKE, Pod Identity on AKS). Overly broad role permissions turn a single pod compromise into a cloud-account compromise.

A common production pattern showing the failure mode:

# Bad: pod's IRSA role has s3:* on *
apiVersion: v1
kind: ServiceAccount
metadata:
  name: analytics-pod
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/analytics-pod-role
# analytics-pod-role policy:
# Action: s3:*
# Resource: "*"

The correct version scopes both the action and the resource:

# Good: scoped to specific S3 bucket and specific actions
# analytics-pod-role policy:
# Action: ["s3:GetObject", "s3:PutObject"]
# Resource: ["arn:aws:s3:::analytics-data-bucket/*"]

Network policy and segmentation (Checks 45-49)

Network policy is the layer that limits lateral movement within the cluster. Without it, a compromised pod can reach every other pod, every internal service, and often the cloud metadata endpoint.

#CheckSeverityWhat attackers exploit when this fails
45Default-deny network policy in every production namespaceCriticalUnrestricted lateral movement on cluster compromise
46Egress restricted (no arbitrary outbound from pods)HighData exfiltration; C2 callbacks; cryptocurrency mining
47Cloud metadata endpoint blocked at network policy level (169.254.169.254)CriticalIMDS abuse for credential theft (especially on EKS without IMDSv2 only)
48Service mesh mTLS enabled if mesh is deployedMediumCleartext inter-service traffic; spoofing
49Network policies tested via automated policy verification toolMediumPolicy drift; rules that don’t actually do what they claim

Check #47 is a top-3 finding by frequency in production audits. The instance metadata endpoint accessible from pods, combined with IMDSv1 enabled on the node, allows credential theft via SSRF in any pod-hosted application — a single XSS payload becomes cloud credential theft. Block at the network policy level:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-imds
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except: [169.254.169.254/32]

Combined with enforcing IMDSv2-only at the node level, this closes one of the most common cloud-to-container escalation paths.

Observability and detection (Check 50)

The single most underutilised check, treated as one because the detection coverage need is unitary — either you’d see an attack on a container or you wouldn’t.

#CheckSeverityWhat attackers exploit when this fails
50Runtime detection deployed (Falco, Tetragon, or equivalent) with alerts routed to SOCHighContainer compromise proceeds without detection; long dwell time

Runtime detection at the container layer is meaningfully different from log-based detection. Falco watches kernel-level syscalls; Tetragon watches eBPF-level events. They catch behaviours like:

  • Shell spawned inside a container that should never have an interactive shell
  • Outbound connection to an unexpected IP from a workload pod
  • Process executing from a writable filesystem location
  • Sensitive file read (e.g., /etc/shadow from inside container)
  • Privileged operation by a container that has no business doing it

Without runtime detection, the dwell time between container compromise and discovery is typically measured in weeks. With it, the same compromise is caught in minutes.

For organisations layering on broader detection, the runtime telemetry plugs into managed SOC monitoring and continuous vulnerability management. The AWS-native detection layer documented in our Security Hub vs GuardDuty vs Inspector comparison covers complementary categories.

What to fix first — severity matrix

After running the 50 checks, the question is sequencing. The matrix that works in practice:

Finding categoryFix priorityWhy
Privileged containers in production (#17)Day 1Direct host compromise risk
Host path mounts (#22) and host network (#23)Day 1Cluster-wide blast radius
Cluster admin RBAC over-grants (#39)Day 1-3Service account compromise = cluster takeover
IRSA / Workload Identity over-permissioned (#40)Day 1-3Pod-to-cloud lateral movement
Metadata endpoint not blocked (#47)Day 1-3SSRF-to-credential-theft pipeline
Default-deny network policy missing (#45)Week 1Lateral movement enabler
Pod Security Admission not enforced (#26)Week 1-2Central enforcer for half the runtime checks
Image signing not enforced (#13)Week 2-3Supply-chain attack surface
Runtime detection not deployed (#50)Week 2-4Closes the dwell-time gap
Secrets stored as plain k8s secrets (#41)Week 3-4Easier than it sounds with External Secrets Operator
CIS Benchmark remediations (#36)Month 2Long tail; lower individual blast radius
SBOM generation and retention policy (#8, #15)Month 2-3Supports incident response when CVE disclosures land

The pattern across mature container security programmes: the day-1 fixes drop risk by 50-60%; the week-1+ fixes drop it another 20-30%; the month-2+ fixes pick up the long tail. Front-load the high-blast-radius work.

Continuous controls after the audit

The 50 checks produce a point-in-time view. The view ages out fast — new workloads, new images, new RBAC bindings land every day. Sustaining the audit’s improvements requires continuous controls.

The minimum continuous controls

  • Admission control via Kyverno or OPA Gatekeeper enforcing the most critical of the 50 checks (no privileged, no host mounts, signed images, scoped service accounts) as Deny rules
  • Pod Security Admission set to restricted in production namespaces, baseline elsewhere
  • Image scan + signature verification gate in the CI pipeline, failing the build on critical findings
  • Runtime detection (Falco/Tetragon) with alerts routed to a SIEM and triaged
  • Quarterly RBAC review — list every cluster-admin and high-permission RoleBinding, justify or remove
  • Quarterly cluster CIS benchmark scan with delta tracking against last quarter
  • Periodic image inventory cleanup — registry retention, unused image removal

For broader context on how these controls fit into a complete cloud security program, the cloud security assessment service walks through the operational sequencing. Layered together, the controls turn the audit from an annual exercise into an ongoing programme that keeps the risk reduction durable.

The argument was never whether containers can be secured. They can be. The argument is whether the secured state survives contact with production engineering velocity — and the difference between programmes that hold the line and programmes that drift is whether the continuous controls listed above are actually running, not just documented. The 50 checks are the snapshot; the continuous controls are the system. Most teams that audit once and then drift end up with the same audit findings the next year, just with different workload names attached.

#Containers #Kubernetes #Cloud Security #Audit #DevSecOps

Related articles

Need expert help with Cloud Security?

Our certified security team is ready to assess your environment and recommend the right solutions.

Book a Free Consultation