In February 2018, Tesla's AWS environment was breached — not through a vulnerability in Tesla's application code, but through an unsecured Kubernetes dashboard exposed to the internet.
The attackers found the dashboard with no authentication required, discovered AWS credentials stored in a pod environment variable, and used those credentials to spin up EC2 instances for cryptocurrency mining.
The pod was also running with more privileges than it needed, making lateral movement trivial. Tesla's breach combined three of the most common Kubernetes security failures into a single incident: exposed management interfaces, credentials in environment variables, and excessive pod privileges.
Kubernetes has become the dominant container orchestration platform — powering production workloads at over 70% of Fortune 500 companies. Its complexity is also its main security challenge. A single Kubernetes cluster can have dozens of nodes, hundreds of pods, thousands of container images, a shared network plane, a secrets store, and an API server that is the central control point for everything. Each layer introduces its own attack surface.
Misconfiguration at any layer — RBAC, pod security, network policy, secrets handling, the supply chain — can give an attacker a path from a compromised container to cluster-admin privileges and, from there, to every workload in the cluster.
This guide covers Kubernetes security from the cluster API server to the container runtime: the attack techniques used against real Kubernetes deployments, the hardening controls that stop them, RBAC design, Pod Security Standards, network policy, secrets management, supply chain security with image signing and scanning, runtime threat detection with Falco, and the CIS Kubernetes Benchmark hardening checklist.
- Kubernetes attack surface — the threat model
- RBAC — Role-Based Access Control hardening
- Pod Security Standards — restricting container privileges
- Network policy — zero-trust networking in Kubernetes
- Secrets management — beyond Kubernetes Secrets
- Supply chain security — image scanning and signing
- API server and etcd hardening
- Runtime security — Falco and eBPF threat detection
- Managed Kubernetes (EKS, GKE, AKS) — provider-specific controls
- CIS Kubernetes Benchmark — hardening checklist
- Frequently asked questions
The Kubernetes attack surface spans seven distinct layers. Each layer has its own set of attack techniques and defences. Understanding the complete threat model before diving into individual controls is essential — Kubernetes security failures are almost always the result of securing some layers while leaving others open.
The most common Kubernetes attack path is not a single catastrophic vulnerability — it is a chain of individually minor-seeming misconfigurations that together produce cluster compromise. Understanding this chain helps prioritise which controls matter most.
Every step in this chain corresponds to a control that can break it: Pod Security Standards eliminate privileged containers; RBAC least-privilege stops SA token abuse; network policy blocks lateral movement; Falco detects the shell spawned after initial access. The controls in this guide address each step.
Kubernetes RBAC controls who (users, groups, service accounts) can do what (verbs: get, list, create, delete, etc.) to which resources (pods, secrets, configmaps, etc.) in which scope (namespace or cluster-wide). RBAC misconfiguration is the most exploited Kubernetes vulnerability class — particularly over-permissive service account tokens automatically mounted into every pod by default.
Pod Security Standards (PSS) replaced Pod Security Policies (deprecated in 1.21, removed in 1.25) as Kubernetes' built-in mechanism for restricting what pod specs can request. PSS defines three profiles applied via namespace labels — the Pod Security Admission controller enforces them at admission time.
| Profile | What it blocks | What it allows | Target use |
|---|---|---|---|
| privileged | Nothing — no restrictions | All pod capabilities including host namespaces, privileged containers, any volume | Trusted system workloads, node agents only (never application pods) |
| baseline | Known privilege escalation vectors: privileged containers, hostPID, hostIPC, hostNetwork, specific dangerous capabilities (SYS_ADMIN, NET_ADMIN, etc.) | Most application patterns; some capabilities (NET_BIND_SERVICE); most volume types | Default for application namespaces — minimum acceptable for production apps |
| restricted | Everything in baseline PLUS: running as root, allowPrivilegeEscalation, most capabilities, hostPath volumes, unsafe sysctls | Only what modern, well-designed container workloads actually need | Production applications — target for all new workloads |
A container running with privileged: true has nearly unrestricted access to the host node. It can mount the host filesystem, load kernel modules, bypass all namespace isolation, and escape to the underlying node OS with root privileges. From the node, the attacker can access the kubelet credentials, read all secrets from other pods on the node, and move to cluster-admin via the node's TLS certificates. Privileged containers are the container equivalent of sudo bash — never acceptable in application pods, and even for system workloads (CNI plugins, storage drivers) should use the minimum capabilities needed rather than full privileged mode.
By default, Kubernetes networking is flat and fully open — every pod can reach every other pod in the cluster on any port. This means a compromised pod can probe and attack every other workload in the cluster without any network-level barrier. NetworkPolicy resources implement micro-segmentation — defining exactly which pods can communicate with which other pods on which ports.
Standard Kubernetes NetworkPolicy operates at Layer 3/4 — IP addresses and ports. Cilium extends this to Layer 7 — HTTP methods, paths, gRPC services, and DNS names. This enables policies like "allow POST to /api/submit but not DELETE to /api/admin" or "allow DNS queries to *.company.com but block all other external DNS."
For production workloads, secrets should live in a dedicated secret store (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager) and be injected into pods at runtime — never stored in etcd at all. Two patterns achieve this:
The container supply chain — the path from source code to running container — is one of the most actively attacked surfaces in 2026. Supply chain attacks against container images include: injecting malicious layers into public base images, compromising CI/CD pipelines to inject code before build, pushing backdoored versions of popular Helm charts to public repositories, and typosquatting popular image names on Docker Hub.
Static security controls (RBAC, Pod Security Standards, NetworkPolicy) prevent attacks by restricting what is possible. Runtime security detects attacks that succeed despite those controls — a zero-day exploit that bypasses pod security, a compromised but legitimate container image, or an insider threat with legitimate access who abuses it. Falco is the CNCF standard for Kubernetes runtime security.
| Control | EKS (AWS) | GKE (Google) | AKS (Azure) |
|---|---|---|---|
| API server access | Private endpoint + security groups; public endpoint should be IP-restricted or disabled | Private cluster mode; authorized networks for public access; control plane IP ranges | Private cluster; API server authorized IP ranges; integration with Azure Firewall |
| Node IAM / identity | Node instance profiles — use IRSA (IAM Roles for Service Accounts) for pod-level IAM; disable IMDSv1 | Workload Identity — pods get Google SA tokens; disable legacy metadata API access | Workload Identity / AAD Pod Identity (deprecated) → Azure Workload Identity (new) |
| Secrets management | AWS Secrets Manager + External Secrets Operator or Secrets Store CSI driver with AWS Secrets Manager provider | GCP Secret Manager + Secrets Store CSI driver or Workload Identity-authenticated access | Azure Key Vault + Secrets Store CSI driver with Azure Key Vault provider |
| Image scanning | Amazon ECR image scanning (Trivy-based) on push; Inspector for continuous scanning | Artifact Registry vulnerability scanning; Binary Authorization for admission control | Azure Container Registry with Defender for Containers; image scanning on push |
| Image signing/policy | ECR + Signer + Kyverno or OPA Gatekeeper for admission policy | Binary Authorization — GKE-native admission control with attestations; supports Cosign | Azure Policy for Kubernetes; Defender for Containers image integrity |
| Runtime protection | Amazon GuardDuty for EKS — runtime threat detection; EKS Audit Log threat detection | GKE Security Posture — built-in Falco-based runtime detection; Threat Detection | Microsoft Defender for Containers — runtime threat detection, audit log analysis |
| Network policy | Calico (self-managed) or VPC CNI with Network Policy controller (released 2023) | GKE Dataplane V2 (Cilium-based) — built-in NetworkPolicy enforcement + L7 policy | Azure CNI with Calico or Azure Network Policy Manager (Calico subset) |
| Node OS hardening | Bottlerocket OS — minimal, read-only OS designed for containers; SELinux enforced | Container-Optimized OS (COS) — minimal, verified boot, auto-updated | Azure Linux (CBL-Mariner) — minimal container host OS option |
| CIS compliance scan | kube-bench with EKS profile; AWS Security Hub has Kubernetes findings | GKE Security Posture Dashboard; kube-bench with GKE profile | Microsoft Defender for Cloud — CIS benchmark for AKS; kube-bench AKS profile |
- ✓RBAC enabled — authorization-mode must include RBAC, never AlwaysAllow — verify: kubectl api-versions | grep rbac and check API server flags.
- ✓API server anonymous auth disabled — --anonymous-auth=false. Anonymous access allows unauthenticated discovery of cluster info.
- ✓etcd access restricted to localhost / API server only — netstat -tlnp | grep 2379 must show 127.0.0.1, not 0.0.0.0. etcd exposure = instant cluster compromise.
- ✓No privileged containers in application namespaces — enforce via Pod Security Standards (restricted profile). Scan existing: kubectl get pods -A -o json | jq '...' (command in Section 3).
- ✓No cluster-admin bindings to non-system accounts — run the clusterrolebinding audit command in Section 2. Every human user having cluster-admin is a critical risk.
- ✓Kubernetes dashboard not exposed without authentication — if the dashboard is deployed, it must require authentication and ideally be accessible only via kubectl proxy (never exposed via a LoadBalancer service).
- ✓Kubelet anonymous auth disabled — --anonymous-auth=false in kubelet config. Exposed kubelet port 10250 without auth = exec into any pod on the node.
- ✓Block access to cloud metadata API from pods — NetworkPolicy blocking 169.254.169.254 for all pods that do not need it. SSRF in any pod + metadata API = node IAM credentials.
- ✓Pod Security Standards — enforce baseline or restricted on all namespaces — start with warn mode to identify non-compliant pods, fix them, then enforce.
- ✓Default-deny NetworkPolicy applied to all application namespaces — then explicitly allow required communication paths (see Section 4).
- ✓Disable automount of service account tokens on pods that don't need API access — patch the default SA in every namespace: kubectl patch sa default -p '{"automountServiceAccountToken":false}'.
- ✓Enable etcd encryption at rest for Secrets — EncryptionConfiguration with aescbc or better KMS provider. Then re-encrypt all existing secrets.
- ✓Image vulnerability scanning in CI/CD pipeline — Trivy or Grype as a blocking step on HIGH/CRITICAL CVEs. No unscanned images should reach production.
- ✓Deploy Falco for runtime threat detection — at minimum: alert on shell in container, crypto miner, sensitive file read, and unexpected privilege escalation.
- ✓Enable Kubernetes API server audit logging — with the audit policy from Section 7. Forward to SIEM (Splunk, Elasticsearch) for retention and alerting.
- ✓Set resource requests and limits on all containers — prevents a compromised container from consuming all node resources (DoS). Also required for Kubernetes scheduler efficiency.
- ✓Image signing with Cosign + admission policy enforcement — only signed images from your registry admitted to production namespaces via Kyverno or Binary Authorization.
- ✓Migrate to external secret store — HashiCorp Vault, AWS Secrets Manager, or cloud-native equivalent. Stop storing production secrets in Kubernetes Secrets/etcd.
- ✓Pin all image references to immutable digests — replace :latest and mutable tags with @sha256:... digests in all production manifests. Use tools like crane digest to resolve tags to digests.
- ✓Seccomp RuntimeDefault on all containers — adds syscall filtering for ~30 dangerous calls. Enable via Pod Security Standards restricted profile or explicit securityContext.
- ✓OPA Gatekeeper or Kyverno policy library — enforce organisational standards: required labels, approved registries, no latest tags, minimum replicas, required resource limits.
- ✓Use IRSA / Workload Identity for pod cloud IAM permissions — remove node-level instance profiles that grant all pods on a node cloud permissions. Scope cloud IAM per service account.
- ✓Node OS hardening — use minimal container-optimised OS (Bottlerocket, COS, CBL-Mariner). Disable SSH access to nodes; use SSM Session Manager or cloud provider equivalent instead.
⚡ Priority actions — start this week
- Run kube-bench against your cluster today — it takes under five minutes and gives you a scored report against the CIS Kubernetes Benchmark across all control categories. The output tells you exactly which flags are missing on your API server, which RBAC issues exist, and which node configurations need fixing. Run it on the control plane node: docker run --pid=host --network=host aquasec/kube-bench:latest. Focus on the FAIL results — these are your immediate priorities.
- Audit cluster-admin bindings immediately — run kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name=="cluster-admin")' and review every result. Any human user, non-system service account, or external identity with cluster-admin is a critical finding. Reduce to the minimum — ideally only the provisioning service account and break-glass accounts.
- Apply Pod Security Standards in warn mode to all namespaces — this is non-breaking (warn mode does not reject pods) but immediately shows which running workloads violate the baseline or restricted profile: kubectl label namespace --all pod-security.kubernetes.io/warn=baseline. Review the warnings collected over 24 hours, fix non-compliant pods, then escalate to enforce.
- Deploy Trivy in your CI/CD pipeline as a blocking step — add Trivy image scanning to every container build pipeline with --exit-code 1 --severity CRITICAL. This immediately stops images with critical CVEs from reaching your registry. Takes 30 minutes to add to a GitHub Actions or GitLab CI pipeline and requires no cluster changes.
- Connect Kubernetes security to your broader cloud and identity posture — Kubernetes security does not exist in isolation. Cloud IAM misconfigurations in the underlying account give attackers node-level access that bypasses all Kubernetes controls; network segmentation at the VPC level complements NetworkPolicy. Cloud pentest → | AWS security → | Network segmentation → | DevSecOps →
Kubernetes RBAC (Role-Based Access Control) controls which users, groups, and service accounts can perform which operations (get, create, delete, exec, etc.) on which resources (pods, secrets, configmaps, etc.) in which scope (namespace or cluster-wide). It is the primary access control mechanism for the Kubernetes API. RBAC is critical because the Kubernetes API is the control plane for everything in the cluster — a misconfigured RBAC rule that grants too much access to a compromised pod or user provides a direct path to cluster takeover. Common misconfigurations include: wildcard permissions, over-broad secrets access, pods/exec granted to developers cluster-wide, and automatic mounting of service account tokens into pods that do not need API access. Running rbac-tool and rakkess regularly helps identify excessive permissions before attackers exploit them.
Pod Security Standards (PSS) is the Kubernetes-native mechanism for restricting what pod specifications can request. It replaced Pod Security Policies (deprecated in 1.21, removed in 1.25) and is enforced by the Pod Security Admission controller built into Kubernetes since 1.23. PSS defines three profiles: privileged (no restrictions — only for trusted system workloads), baseline (blocks known privilege escalation vectors like privileged containers, hostPID, hostIPC, dangerous capabilities), and restricted (everything in baseline plus: no running as root, no privilege escalation, read-only root filesystem, all capabilities dropped, seccomp required). Profiles are applied via namespace labels in three modes: enforce (reject non-compliant pods), audit (allow but log), and warn (allow but show warning). Target: restricted profile enforced on all production namespaces.
Not by default. Kubernetes Secrets are stored in etcd as base64-encoded values — base64 is encoding, not encryption, and can be trivially reversed. Anyone with access to etcd or a Kubernetes role that grants secrets/get can read them. Encryption at rest must be explicitly enabled via an EncryptionConfiguration that tells the API server to encrypt secrets before writing to etcd. The EncryptionConfiguration supports multiple providers: aescbc (AES encryption with a key stored on the API server node), aesgcm, and KMS (delegates key management to a cloud KMS service like AWS KMS or GCP Cloud KMS — the strongest option because the encryption keys are never stored on the cluster itself). For production workloads, the recommended approach is using an external secret store (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) so secrets never touch etcd at all.
Falco is a CNCF open-source runtime security tool that monitors system calls in real time using eBPF (or a kernel module) and alerts on suspicious behaviour matching configurable rules. In Kubernetes environments, Falco runs as a DaemonSet on each node and detects: shells spawned inside containers (indicating active compromise or exploitation), cryptocurrency miners, reads of sensitive files (credential theft), unexpected network connections, privilege escalation attempts, container escape activities, and anomalous process execution. Falco complements static controls (RBAC, Pod Security Standards, NetworkPolicy) by detecting attacks that succeed despite those controls — zero-day exploits, compromised legitimate images, or misuse of legitimate access. Falco output can be sent to Slack, PagerDuty, Splunk, Elasticsearch, and 50+ other destinations via Falcosidekick.
Container supply chain security refers to securing the entire path from source code to running container: the base images used, the build pipeline, the container registry, and the admission of images into the cluster. Threats include: malicious packages injected into base images (as in the XZ Utils backdoor, 2024), compromised CI/CD pipelines that modify images after build, typosquatting of popular image names on public registries, and outdated base images with known CVEs. Best practices: scan all images for vulnerabilities with Trivy during CI (blocking on HIGH/CRITICAL); sign images with Cosign (Sigstore) after build; verify signatures at admission with Kyverno or Binary Authorization; pin production images to immutable SHA256 digests rather than mutable tags; maintain a Software Bill of Materials (SBOM) for all production images; and allow only images from your own private registry in production namespaces.
Kubernetes NetworkPolicy is a namespaced resource that defines allow rules for pod network communication — specifying which pods can send traffic to or receive traffic from which other pods, on which ports. By default, Kubernetes networking is fully open — all pods can reach all other pods. NetworkPolicy implements micro-segmentation. The most important first step is deploying a default-deny-all policy in each namespace, then explicitly allowing required communication paths. Critically, NetworkPolicy objects are only enforced if the cluster's CNI (Container Network Interface) plugin supports them — Flannel does not. CNI plugins that enforce NetworkPolicy include: Calico, Cilium, Weave Net, Antrea, and the cloud-provider native CNIs on EKS, GKE, and AKS. Cilium extends NetworkPolicy to Layer 7 (HTTP methods, gRPC, DNS) for even more granular control.