Over 60%
of production Kubernetes clusters have at least one container running with privileged access or root capabilities
94%
of container security incidents involve lateral movement to other containers or nodes after initial compromise
Less than 30%
of Kubernetes deployments have NetworkPolicy resources defined to restrict east-west traffic between pods
Average $1.2M
estimated cost to recover from a Kubernetes cluster compromise including forensics, remediation, and business disruption

SponsoredRetool

Retool's new app builder is where AI-generated code ships safely

Building apps with AI is easy. Getting them to production safely is another story.

Start building for free today

Most production Kubernetes clusters were built for velocity, not security. The developer who set up the cluster two years ago needed applications running quickly, so containers were deployed without securityContext restrictions, RBAC was configured with broad permissions to avoid troubleshooting friction, NetworkPolicies were never implemented because the initial deployment worked fine without them, and hostPath volume mounts were used liberally because they were convenient. The cluster worked. The applications ran. Nobody noticed the security debt accumulating in the configuration. Until now, when a security team has inherited the cluster and the mandate to harden it without breaking the applications that the business depends on. This guide addresses the four highest-risk Kubernetes misconfigurations with a hardening approach that prioritizes audit-before-enforce methodology, graduated rollout by namespace, and practical exception handling for workloads that genuinely need elevated permissions. The sequence matters as much as the individual controls, and the sequence described here is designed to produce measurable security improvement at each stage without triggering the production incidents that cause hardening projects to be deprioritized.

The Four Highest-Risk Default Misconfigurations

Kubernetes clusters inherited without deliberate security hardening consistently present the same four categories of misconfiguration, and they compound each other. A container running as root is more dangerous when it also has a NetworkPolicy-free path to the cluster API server. An over-privileged service account is more exploitable when containers have unrestricted network access to internal services.

Privileged containers are the most direct path from a container compromise to a node compromise. A container running with privileged: true has access to the host's kernel capabilities, device files, and namespaces. An attacker who achieves code execution in a privileged container can trivially escape to the underlying node, access other containers' filesystems, and potentially pivot to the control plane. Even without the privileged flag, containers running as root with the default capability set have capabilities like CAP_NET_ADMIN, CAP_SYS_PTRACE, and others that enable meaningful container escape paths.

Absent NetworkPolicies mean that every pod in the cluster can communicate with every other pod by default. In a Kubernetes cluster with no NetworkPolicies, a compromised frontend pod has direct network access to database pods, internal APIs, the cluster metadata service, and any other pods in any namespace. Real environments need east-west traffic controls that reflect the actual communication requirements of the application architecture, not a default-allow model.

Wildcard RBAC and cluster-admin bindings are the third category. The default Kubernetes RBAC configuration does not grant broad permissions, but in practice, clusters accumulate bindings that do. Service accounts with get, list, watch on all resources in all groups are common. ClusterRoleBindings to cluster-admin for CI/CD service accounts are common. These broad permissions mean that compromising a single application pod with an over-privileged service account gives an attacker enumeration or modification access to the entire cluster's resources.

HostPath volume mounts are the fourth category. A container with a hostPath mount to the node's root filesystem, Docker socket, or kubelet credential directory can read node-level secrets, modify node configuration, or interact with the container runtime in ways that compromise other containers running on the same node.

Pod Security Standards: The Replacement for PodSecurityPolicy

PodSecurityPolicy (PSP) was deprecated in Kubernetes 1.21 and removed in 1.25. The replacement is Pod Security Admission (PSA), implemented through the Pod Security Standards framework. PSA is built into the Kubernetes API server as an admission controller and does not require installing a separate admission webhook, which simplifies deployment significantly compared to PSP.

The three Pod Security Standard profiles are: Privileged (no restrictions, equivalent to no policy), Baseline (prevents the most dangerous settings: privileged containers, host namespaces, host path mounts, and dangerous capabilities), and Restricted (adds requirements for non-root containers, seccomp profiles, and a minimal capability set). The Restricted profile is the target state for most application workloads. The Baseline profile is appropriate for infrastructure workloads like logging agents and monitoring tools that need elevated permissions but not full privilege.

PSA is enforced at the namespace level using labels. The three label modes are: warn (adds a warning to API responses but allows the pod to create), audit (records a violation in the audit log but allows the pod to create), and enforce (rejects pods that violate the profile). The three modes map directly to the audit-before-enforce methodology: start with warn and audit to understand the baseline, then move to enforce. The label syntax for a namespace is: pod-security.kubernetes.io/enforce: restricted for enforcement and pod-security.kubernetes.io/audit: restricted for audit mode. Multiple modes can be active simultaneously at different levels.

Subscribe to unlock Remediation & Mitigation steps

Free subscribers unlock full IOC lists, Sigma detection rules, remediation steps, and every daily briefing.

Free daily briefing

Briefings like this, every morning before 9am.

Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.

Non-Root Containers: Why Most Images Need Rebuilding

Enabling the Restricted pod security profile is straightforward in configuration. The reality is that a substantial fraction of container images in production clusters cannot meet the Restricted requirement without modifications to the container image itself. Most default base images run processes as root (UID 0) unless explicitly configured otherwise, and many application images have startup scripts, file permission requirements, or listening port configurations that assume root execution.

The securityContext fields that implement non-root execution are: runAsNonRoot: true (prevents the container from running if the image would run as root), runAsUser (specifies the UID to run as), runAsGroup (specifies the GID), and allowPrivilegeEscalation: false (prevents setuid or setgid binaries from elevating privileges). The capabilities section removes capabilities from the default set: dropping ALL and then adding back only the specific capabilities needed.

For most commercial application workloads, the practical path is to add a non-root user to the Dockerfile (RUN addgroup -S appgroup && adduser -S appuser -G appgroup in Alpine-based images), change ownership of any directories the application needs to write to, configure the application to bind to a non-privileged port (above 1024) if it previously listened on port 80 or 443, and set USER appuser before the CMD or ENTRYPOINT instruction. For third-party images where you do not control the Dockerfile, check whether the vendor provides a non-root image variant, and if not, create a wrapper image that runs the third-party image under a non-root user with appropriate filesystem permissions.

NetworkPolicy: Default-Deny Without Breaking Everything

NetworkPolicy resources are Kubernetes objects that define ingress and egress rules for pods based on labels, namespace selectors, and IP address ranges. Without any NetworkPolicy defined in a namespace, all pod-to-pod communication is permitted (default-allow). Once a NetworkPolicy selects a pod, that pod becomes subject to the policy, and any traffic not explicitly permitted is denied. This is the critical design behavior: applying a default-deny NetworkPolicy to a namespace immediately blocks all traffic for any pod that the policy selects.

The staged approach to NetworkPolicy rollout is essential to avoid production incidents. The sequence is: start by auditing actual traffic flows (using your CNI plugin's traffic logging if available, or temporarily enabling network flow logs), map the required communication paths for each application, create allow rules for each required path, apply the policies in audit mode if your CNI supports it (Cilium's DENY action with metrics provides this), verify that the allow rules cover all legitimate traffic, and only then apply the default-deny policy.

The default-deny manifest that should be applied to each namespace once allow rules are confirmed is a NetworkPolicy with an empty podSelector (matching all pods) and an empty ingress array (denying all ingress). A matching egress-deny policy should be applied for outbound traffic control. Apply these last, after the allow policies for each application are confirmed to be working. Never apply the default-deny as the first step in a namespace unless it contains no running workloads.

Subscribe to unlock Remediation & Mitigation steps

Free subscribers unlock full IOC lists, Sigma detection rules, remediation steps, and every daily briefing.

RBAC Audit: Identifying Wildcard Verbs and Cluster-Admin Bindings

Kubernetes RBAC audit starts with enumerating all ClusterRoleBindings and RoleBindings to identify accounts with excessive permissions. The kubectl command kubectl get clusterrolebindings -o json | jq '.items[] | select(.roleRef.name == "cluster-admin")' lists every binding to the cluster-admin role, which grants unrestricted access to every API in the cluster. In most production clusters, the list will include some expected system accounts and at least a few unexpected ones: CI/CD service accounts, monitoring tools, and sometimes user accounts that were granted cluster-admin for a one-time task and were never revoked.

For non-cluster-admin bindings, look for roles with wildcards in the verbs, resources, or apiGroups fields. A role with verbs: [""] can perform any action on its resources. A role with resources: [""] can act on any resource type in its API group. The combination of wildcard verbs and wildcard resources in a role effectively grants cluster-admin for the specified API groups. These wildcard permissions are often created by infrastructure tools during installation and then never tightened.

The remediation approach for RBAC is to apply the principle of least privilege: for each service account and user account, determine what API actions it actually requires, create a new Role or ClusterRole with only those specific permissions, and replace the existing binding with a binding to the new least-privilege role. The Rakkess and kubectl-who-can tools from Aqua Security are useful for visualizing what permissions each service account currently has. Start with the CI/CD service accounts and monitoring agents that are most commonly over-privileged, and work through the list by risk impact.

Secrets Management: etcd Encryption and External Secrets

Kubernetes Secrets are base64-encoded, not encrypted, in etcd by default. Any user who can read the etcd data directory or has get permissions on Secret objects can trivially decode the content. The first mitigation is enabling encryption at rest for etcd using the EncryptionConfiguration API, which encrypts Secret objects in etcd using AES-CBC or AES-GCM before writing them to disk. This protects against the scenario where the etcd data files are accessed directly (through a backup, through a node compromise, or through a misconfigured etcd API endpoint).

Encryption at rest does not protect against in-cluster access to Secret objects via the Kubernetes API. A service account with get permissions on Secrets in a namespace can read any Secret in that namespace via kubectl get secret or the API. The complete solution to this is moving secrets out of Kubernetes Secrets and into an external secrets manager: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, or GCP Secret Manager. The External Secrets Operator provides a CRD-based interface for synchronizing secrets from these external systems into Kubernetes Secrets on demand, enabling fine-grained access control at the secrets manager level while maintaining compatibility with workloads that consume Kubernetes Secrets.

For teams not ready to migrate to an external secrets manager, the immediate steps are: enable etcd encryption at rest, audit RBAC to ensure only specific workloads have get permissions on Secrets in each namespace, and avoid mounting service account tokens as environment variables (use projected service account tokens with short TTLs instead).

Falco for Runtime Detection: The Rules That Matter

Falco is the CNCF-graduated runtime security tool that monitors system calls from containers and generates alerts when application behavior deviates from expected patterns. Falco rules are written in a YAML-based condition language that evaluates system call metadata: process name, file path, network connections, user ID, container image, and namespace. The default Falco rule set covers the most common attacker behaviors observed in container environments.

The rules that have the highest signal-to-noise ratio in production clusters: Terminal shell in container (a shell being spawned in a running production container is almost always either an attacker or an operator debugging in production, and both scenarios warrant attention), Container running as root with unexpected network connections, Sensitive file read by unexpected process (reading /etc/shadow, /root/.ssh, or Kubernetes service account token files from a process that has no business doing so), and Unexpected outbound connections (containers making outbound connections to IPs that are not in their expected external dependency list). The drift detection rules that identify container filesystem modifications are also high-value for detecting active compromise.

Falco's output can be forwarded to SIEM platforms, Slack, PagerDuty, or any webhook-compatible destination via Falcosidekick. The operational challenge is alert volume: a busy cluster with many legitimate operations will generate significant Falco noise from the default rules without tuning. The recommended approach is to start with only the highest-confidence rules (terminal shells, sensitive file reads, privilege escalation attempts) and expand coverage gradually as the baseline is established and known-legitimate behaviors are allowlisted.

Subscribe to unlock Remediation & Mitigation steps

Free subscribers unlock full IOC lists, Sigma detection rules, remediation steps, and every daily briefing.

The Hardening Sequence: Order of Operations Matters

The hardening sequence is not arbitrary. Each step builds on the previous one, and starting in the wrong order creates either production incidents or security controls that can be bypassed because a prerequisite control is missing. The recommended sequence is: PSA audit mode first, then RBAC cleanup, then NetworkPolicies, then non-root migration last.

Start with PSA audit mode because it gives you immediate visibility into which workloads have the highest-risk security configurations without causing any disruption. Apply pod-security.kubernetes.io/audit: restricted and pod-security.kubernetes.io/warn: restricted to every namespace and run for one to two weeks. The audit log violations give you the workload-by-workload list of required changes. This data drives the prioritization of everything that follows.

RBAC cleanup comes second because it reduces the blast radius of any compromise that occurs during the remaining hardening steps. If a workload is temporarily exploitable during the non-root migration, an attacker who achieves code execution in that workload should face a service account with minimal RBAC permissions rather than one that can list secrets across the cluster.

NetworkPolicies come third because they require the most careful traffic flow analysis and the longest audit period. Start with the least sensitive namespaces (staging, development) to develop confidence in the process before applying NetworkPolicies to production namespaces. The default-deny policies for each production namespace should be the final step of the NetworkPolicy rollout.

Non-root migration comes last because it has the highest risk of breaking application functionality and requires coordination with development teams to update container images. Use the PSA audit data from step one to prioritize which workloads need immediate attention versus which can be addressed in the next release cycle.

The bottom line

A Kubernetes cluster where everything runs as root, has no NetworkPolicies, and uses wildcard RBAC is not a container platform with a security problem. It is a stepping stone from any one compromised container to the entire cluster and potentially the cloud account it runs in. The hardening sequence described here, audit mode PSA first, then RBAC, then NetworkPolicies, then non-root container migration, is the order that produces measurable improvement at each stage without triggering the production incidents that get hardening projects cancelled. None of these controls are optional for workloads running sensitive data or in regulated environments. The NSA and CISA Kubernetes Hardening Guidance from 2022 covers the same ground with additional detail and is worth reading alongside this guide.

Frequently asked questions

What CNI plugin should we use to support NetworkPolicy enforcement?

The Kubernetes NetworkPolicy API is implemented by CNI plugins, not by Kubernetes itself. The default kubenet CNI does not enforce NetworkPolicies. You need a CNI plugin that supports NetworkPolicy enforcement: Calico, Cilium, Weave Net, and Antrea are the most common options. Cilium additionally provides Layer 7 policy enforcement (HTTP, DNS, gRPC-aware policies), built-in observability through Hubble, and eBPF-based performance improvements. For new clusters, Cilium is the recommended choice. For existing clusters with Calico or Flannel, migrating CNI plugins requires careful planning and is typically done during a maintenance window.

How do we handle stateful applications that require writing to the filesystem as root?

Most stateful applications that appear to require root execution actually require ownership of specific filesystem paths, not root access per se. The solution is to use an init container that runs as root to set up the required directory ownership and permissions, followed by the application container running as a non-root user with the correct ownership already in place. For applications that genuinely cannot run as non-root (legacy database engines, certain JVM applications), configure a namespace-level PSA exception using the Baseline profile instead of Restricted, document the exception with a remediation timeline, and compensate with additional Falco detection rules.

Can we enforce WDAC-style application allowlisting at the Kubernetes level to control which container images can run?

Yes, through admission control. OPA Gatekeeper and Kyverno are the two most commonly used Kubernetes policy engines that can enforce image allowlisting policies. A Kyverno ClusterPolicy that requires container images to come from a specific container registry (your internal registry rather than arbitrary Docker Hub images) combines allowlisting with provenance control. Pair image registry restrictions with image signing verification using Sigstore/Cosign to ensure that only images signed by your build pipeline can run, which addresses both the source and integrity of deployed containers.

What is the risk if we never implement NetworkPolicies but address the other three categories?

The lack of NetworkPolicies specifically enables lateral movement within the cluster after initial compromise. Even if a compromised container runs as non-root with minimal RBAC permissions, it still has unrestricted network access to every other pod in the cluster. This means it can reach database pods, internal APIs, and the Kubernetes API server directly. In environments with a flat cluster network and no east-west controls, a compromised low-privilege frontend container can directly attempt to authenticate to internal services using credentials that may be less hardened than external-facing services. NetworkPolicies are not optional for production clusters with sensitive workloads.

How do we handle Helm charts from third-party vendors that set their own securityContext and often request elevated permissions?

Third-party Helm charts requesting elevated permissions are extremely common and fall into three categories: charts that genuinely need elevated permissions for their function (CNI plugins, storage drivers, monitoring agents), charts that request elevated permissions for convenience rather than necessity, and charts that have not been updated to reflect current security best practices. For each chart, review the securityContext values and override them in your values.yaml where possible to remove unnecessary permissions. For charts where the vendor has not exposed these as configurable values, use a Kustomize patch or admission controller policy to modify them at deployment time. If the vendor refuses to support a hardened deployment configuration, that is a vendor management conversation.

Sources & references

  1. Kubernetes Pod Security Standards Documentation
  2. NSA/CISA Kubernetes Hardening Guidance
  3. CIS Kubernetes Benchmark
  4. Falco Runtime Security Documentation
  5. MITRE ATT&CK for Containers Matrix

Free resources

25
Free download

Critical CVE Reference Card 2025–2026

25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.

No spam. Unsubscribe anytime.

Free download

Ransomware Incident Response Playbook

Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.

No spam. Unsubscribe anytime.

Free newsletter

Get threat intel before your inbox does.

50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.

Unsubscribe anytime. We never sell your data.

Eric Bang
Author

Founder & Cybersecurity Evangelist, Decryption Digest

Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.

Black Hat Giveaway

Win a $2,495 Black Hat pass.

Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.

Joins Decryption Digest daily briefing. Unsubscribe anytime.

Giveaway: Black Hat USA 2026 Full-Access Pass ($2,495 value)

Details →
Daily Briefing

Subscribe to enter the giveaway

Every subscriber is automatically entered. You also get daily threat intel every morning: zero-days, ransomware, and nation-state campaigns. Free. No spam.

Already subscribed? You're already entered.

Giveaway

Win a $2,495 Black Hat USA 2026 pass.