Kubernetes is permissive by default: Secrets are stored unencrypted, audit logging is off, every pod can talk to every other pod and a single over-broad role binding can hand an attacker the whole cluster. The NSA and CISA Kubernetes Hardening Guide names three common sources of compromise: supply chain risks, malicious threat actors and insider threats. This guide covers cluster hardening end to end: the API server, kubelet and etcd, RBAC, Pod Security Standards and admission control, image verification at admission, network policies and multi-tenancy, encryption at rest, audit logging, runtime detection and what changes on managed services such as EKS, AKS and GKE. It is written for platform engineers, cluster operators and security architects. Service account tokens are only summarised here because the live Kubernetes NHI Security Guide covers them in depth.
Key takeaways
- Close the defaults first. Disable anonymous API access, keep the API server, kubelet and etcd off the internet, configure an audit policy and turn on encryption at rest for Secrets; none of these is on by default in a self-managed cluster.
- RBAC is where clusters are really lost. List on Secrets, create on Pods,
escalate,bind,impersonateandnodes/proxyare privilege escalation paths, and the defaulteditrole can read Secrets and run pods as any service account in its namespace. - Enforce Pod Security Standards per namespace. Pod Security Admission (GA since v1.25) applies Baseline or Restricted with namespace labels; roll out in
warnandauditbeforeenforce. - Admission is the supply chain gate. Verify image signatures and pin digests at admission with a policy engine or webhook, so an unsigned or tag-swapped image never runs.
- Default deny, then allow. Pods are reachable from everywhere until a NetworkPolicy selects them, so apply default-deny ingress and egress per namespace and filter access to the cloud metadata API.
The cluster attack surface
The NSA and CISA guide (version 1.2, August 2022) lists the ports below. Every one should be reachable only from the networks that need it, and the Kubernetes security checklist states that "The Kubernetes API, kubelet API and etcd are not exposed publicly on Internet."
| Component | Port | Main risk | Hardening |
|---|---|---|---|
| kube-apiserver | 6443 | Anonymous or over-privileged access to the whole cluster | --anonymous-auth=false, --authorization-mode=Node,RBAC, private endpoint or IP allowlist |
| etcd | 2379-2380 | Direct read of all cluster state, including Secrets | Mutual TLS with a CA unique to etcd, reachable only from the API server |
| kubelet API | 10250 | Command execution in pods, log and Secret access | Anonymous auth off, webhook authorisation, node firewalling |
| kube-scheduler, kube-controller-manager | 10259, 10257 | Control plane tampering, information disclosure | Bind to localhost or control plane network only |
| NodePort Services | 30000-32767 | Workloads exposed on every node unintentionally | Prefer load balancers or ingress with explicit exposure review |
Control plane, API server and kubelet
- Authentication: the NSA and CISA guide states "Anonymous requests should be disabled by passing the --anonymous-auth=false option to the API server". Use OIDC or cloud IAM for humans with MFA, and keep static token files and long-lived client certificates out of daily use.
- Authorisation: run
--authorization-mode=Node,RBACand neverAlwaysAllow. The Node authoriser plus theNodeRestrictionadmission plugin limit each kubelet to its own node and pods. - Bootstrap credentials: the checklist says "system:masters group is not used for user or component authentication after bootstrapping". Membership bypasses RBAC and cannot be revoked by deleting bindings. Protect the root CA offline or in a tightly controlled managed CA.
- Controllers: run kube-controller-manager with
--use-service-account-credentialsso each controller uses its own scoped identity. - Kubelet: set
--anonymous-auth=falseand--authorization-mode=Webhookon every node so kubelet requests go through RBAC, and treatnodes/proxyas powerful: the RBAC good practices state "get permission on nodes/proxy is not a read-only permission." - Admission plugins: keep the defaults, enable
NodeRestrictionandDenyServiceExternalIPs, and considerAlwaysPullImageson multi-tenant clusters so one tenant cannot run another's cached private image. - Dashboards and consoles: never expose the Kubernetes Dashboard or tool UIs such as Kubeflow without authentication. The Tesla Kubernetes Cryptojacking 2018 began with an open console, and the Kubeflow Cryptomining Attacks 2020 combined exposed dashboards with a mounted service account.
etcd and Secrets encryption at rest
The NSA and CISA guide notes that "By default, Secrets are stored as unencrypted base64-encoded strings." Anyone with etcd access or a backup can read them.
- etcd access: mutual TLS between API server and etcd, a CA used only for etcd, no network path from nodes or workloads, and encrypted, access-controlled backups.
- Encryption at rest: pass an
EncryptionConfigurationfile to kube-apiserver with--encryption-provider-config. "The first provider in the list is used to encrypt resources written into the storage", and existing Secrets are only re-encrypted when rewritten, for example withkubectl get secrets --all-namespaces -o json | kubectl replace -f -.
| Provider | What the Kubernetes documentation says | Use |
|---|---|---|
identity | "does not encrypt stored data"; the default if nothing is configured | Only as a last entry during migration |
aescbc | "Not recommended due to CBC's vulnerability to padding oracle attacks" | Avoid for new clusters |
aesgcm | "Not recommended for use except when an automated key rotation scheme is implemented" | Only with automated rotation |
secretbox | Newer cryptography that may not pass high-assurance review | Case by case |
kms v2 | Envelope encryption with an external key manager; KMS v1 deprecated since v1.28 | Preferred for production |
The encryption configuration file "may contain keys that can decrypt content in etcd", so restrict control plane host access. See the Secrets Management Guide for external secret stores.
RBAC: least privilege and escalation paths
The Kubernetes RBAC good practices are direct: "Assign permissions at the namespace level where possible", "Avoid providing wildcard permissions when possible, especially to all resources" and "Administrators should not use cluster-admin accounts except where specifically needed". Wildcards also cover resource types added later by new CRDs.
| Permission | Why it amounts to escalation |
|---|---|
get, list or watch on Secrets | List and watch "effectively allow for users to reveal the Secret contents", including tokens and keys |
create on Pods or workload resources | Run a pod as any service account in the namespace and mount its Secrets |
create on PersistentVolumes | A hostPath volume reaches the node filesystem |
get on nodes/proxy | Direct access to the kubelet API, including command execution |
escalate, bind | Create or bind roles with permissions the user does not hold |
impersonate | Act as another user, group or service account |
| Create and approve CSRs | Issue new client certificates that authenticate to the cluster |
create on serviceaccounts/token | Mint tokens for existing service accounts |
| Write on admission webhook configurations | Read or change any object admitted to the cluster |
patch on Namespaces | Change labels that relax Pod Security Admission or NetworkPolicy selection |
- Default roles: bind
admin,editandviewwith namespace RoleBindings. The RBAC reference warns thatedit"allows accessing Secrets and running Pods as any ServiceAccount in" the namespace;viewdeliberately excludes Secrets. - Aggregated ClusterRoles: a ClusterRole labelled
rbac.authorization.k8s.io/aggregate-to-edit: "true"(or-admin,-view) silently adds its rules to every binding of that default role. One operator chart can wideneditcluster-wide, so review aggregation labels before install. - Persistence via bindings: ATT&CK T1098.006 Additional Container Cluster Roles covers attackers creating RoleBindings or ClusterRoleBindings, and Microsoft's threat matrix lists "Cluster-admin binding". Alert on any new binding to
cluster-admin. - Anonymous groups: remove bindings to
system:unauthenticated, which "gives access to anyone who can contact the API server at a network level". - Review: review bindings periodically; a reused username inherits a deleted user's bindings. See the Cloud PAM and CIEM Guide for cloud IAM roles mapped into clusters.
Service accounts and workload identity
Service accounts are the cluster's main non-human identities. Disable token automounting where pods do not call the API (the checklist: "Service account tokens are not mounted in pods that don't require them"), use bound, projected tokens rather than legacy Secret-based tokens, give each workload its own service account and bind cloud permissions through workload identity federation rather than static cloud keys. ATT&CK T1528 Steal Application Access Token describes the alternative. Token projection, automounting and legacy token clean-up are covered in the Kubernetes NHI Security Guide and the Cloud Workload Identity Guide.
Pod Security Standards and admission control
Pod Security Admission
The Pod Security Standards define three profiles: Privileged ("Unrestricted policy"), Baseline ("Minimally restrictive policy which prevents known privilege escalations") and Restricted ("Heavily restricted policy, following current Pod hardening best practices"). Baseline blocks host namespaces, privileged containers, hostPath volumes, host ports, added capabilities outside a short allowlist and Unconfined seccomp. Restricted adds allowPrivilegeEscalation: false, runAsNonRoot: true, seccomp RuntimeDefault or Localhost, capabilities dropping ALL (adding only NET_BIND_SERVICE) and an allowlist of volume types. Pod Security Admission applies them with namespace labels, one level per mode:
apiVersion: v1
kind: Namespace
metadata:
name: payments
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.34
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
enforce rejects violating pods, audit records an annotation in the audit log and warn returns a warning to the user. Enforcement applies to Pods, not Deployments, so a non-compliant Deployment is accepted and its ReplicaSet then fails to create pods. Exemptions (usernames, RuntimeClass names, namespaces) skip all checks and should be few and documented. Because patch on Namespaces can change these labels, restrict it.
Policy engines and ValidatingAdmissionPolicy
For rules beyond pod fields, such as approved registries, no latest tags or no LoadBalancer Services, use ValidatingAdmissionPolicy, stable since v1.30, which is "a declarative, in-process alternative to validating admission webhooks" written in CEL. A ValidatingAdmissionPolicy holds the logic, a ValidatingAdmissionPolicyBinding scopes it, and validationActions of Deny, Warn or Audit give a built-in dry-run path. Webhook-based engines such as OPA Gatekeeper and Kyverno add mutation, reporting and image verification.
Image verification at admission
The checklist calls for images referenced "by sha256 digests (rather than tags)" or provenance "validated by verifying the image's digital signature at deploy time". Kyverno's verifyImages rules, for example, verify Sigstore cosign or Notary signatures and attestations, and by default rewrite tags to digests (mutateDigest) and require a digest (verifyDigest). Note its documented verification cache (default TTL 60 minutes). Microsoft's threat matrix lists "Compromised image In registry" as an initial access technique; see the SLSA and Build Provenance Guide for what to verify.
Network policies and multi-tenancy
- Default deny: pods accept traffic from anywhere until a NetworkPolicy selects them, and policies only add allowed flows. Apply a policy per namespace that selects all pods and denies all ingress and egress, as both the NSA and CISA guide and the checklist recommend, then allow named flows, including DNS. The CNI plugin must enforce NetworkPolicy, or the objects do nothing.
- Egress and metadata: the checklist requires that "Access from the workloads to the cloud metadata API is filtered". Block
169.254.169.254except for pods that need it; Microsoft's matrix lists "Instance Metadata API" under discovery. - Namespaces are not a hard boundary: for multi-tenancy combine namespaces with RBAC, PSA, NetworkPolicy and ResourceQuota and LimitRange. The checklist places sensitive applications "isolated on nodes or with specific sandboxed runtimes"; use node pools with taints and RuntimeClass for hostile tenants, or separate clusters.
- Ingress and service mesh: ingress controllers are internet-facing and privileged, so patch them as edge software and terminate TLS there. A service mesh adds mutual TLS and identity-based authorisation between services but does not replace NetworkPolicy. See the Network Segmentation Guide.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: payments
spec:
podSelector: {}
policyTypes: ["Ingress", "Egress"]
Audit logging and runtime detection
The NSA and CISA guide warns that "Kubernetes' built-in audit logging capabilities perform no logging by default". Supply --audit-policy-file (if omitted, "no events are logged") and a backend, either --audit-log-path with --audit-log-maxage, --audit-log-maxbackup and --audit-log-maxsize, or a webhook via --audit-webhook-config-file. Levels are None, Metadata, Request and RequestResponse, and "The first matching rule sets the audit level". Log Secrets, ConfigMaps and TokenReviews at Metadata so values never reach the log, log RBAC and workload changes at RequestResponse and drop read-only noise; auditing increases API server memory use. On managed clusters, enable the provider's audit log export.
Runtime tools add what the API cannot see: Falco evaluates syscalls and can ingest Kubernetes audit events through a plugin, and Tetragon is another eBPF option. See the Log Management and Retention Guide.
| ATT&CK v20 technique | Microsoft matrix technique | Detection | Prevent with |
|---|---|---|---|
| T1133 External Remote Services | Exposed sensitive interfaces | External scans of API, kubelet and dashboards | Private endpoints, no anonymous auth |
| T1609 Container Administration Command | Exec into container | Audit events on pods/exec; shell in container | RBAC on pods/exec, distroless images |
| T1610 Deploy Container | Backdoor container | Pod creation by unusual identities or images | Admission policy, image verification |
| T1053.007 Container Orchestration Job | Kubernetes CronJob | New CronJobs outside GitOps | RBAC on workload creation |
| T1098.006 Additional Container Cluster Roles | Cluster-admin binding | Create or update on (Cluster)RoleBindings | Restrict bind and escalate |
| T1611 Escape to Host | Privileged container, Writable hostPath mount | Privileged pods, hostPath, namespace changes | PSA Baseline or Restricted |
| T1552.007 Container API | List K8S secrets | Secret list or watch by unusual identities | RBAC, encryption at rest |
| T1613 Container and Resource Discovery | Access the K8S API server | Bursts of list calls from pods | Token automount off, least privilege |
| T1496 Resource Hijacking | Resource hijacking | CPU spikes, mining pool connections | Quotas, egress policy |
Microsoft's Threat Matrix for Kubernetes uses ten tactics with Kubernetes-specific technique names and mitigations MS-M9001 to MS-M9032, such as "Restrict access to etcd". It does not map to ATT&CK IDs, so the pairing above is ours.
Managed Kubernetes and shared responsibility
On Amazon EKS, AWS is responsible for "the Kubernetes control plane, which includes the control plane nodes and etcd database". The customer keeps data plane configuration, including security groups, "The configuration of the nodes and the containers themselves", node OS patching, network controls and platform-level IAM. Check each provider's own split. You still own RBAC, cloud IAM mappings, API endpoint exposure, PSA, NetworkPolicy, admission, node pools, audit log export and workloads. Fully managed node modes (GKE Autopilot, EKS Auto Mode, AKS Automatic) shift node management further, not workload or RBAC configuration.
Benchmarks and assessment
The CIS Kubernetes Benchmark (version 2.1.0 at the time of writing) has separate variants for EKS, EKS Auto Mode, AKS, AKS Automatic, GKE, GKE Autopilot, OKE and OpenShift; use the managed variant on managed services, where many control plane checks are not visible to customers. kube-bench automates the CIS checks, and OWASP also lists kubeaudit and kubesec for manifests.
Implementation roadmap
- Assess: run kube-bench or provider posture checks; list public endpoints,
cluster-adminbindings and namespaces lacking PSA labels or default-deny policy. - Close exposure: make the API endpoint private or allowlisted, disable anonymous auth, remove public dashboards and unauthenticated tool UIs.
- Turn on audit logging and encryption at rest, re-encrypt existing Secrets and confirm by reading a test Secret directly from etcd in non-production.
- Tighten RBAC: move to namespace bindings, remove wildcards and keep
cluster-adminfor a monitored break-glass account. - Roll out PSA: label all namespaces
warnandauditat Restricted, fix workloads for two to four weeks, thenenforceBaseline everywhere and Restricted where workloads comply; pilot on one non-production cluster first. - Add admission policy in
AuditorWarnmode (registry allowlist, signature verification, digest pinning), then switch toDeny. - Apply default-deny NetworkPolicies namespace by namespace with DNS and known flows allowed, observing dropped traffic before moving on.
- Deploy runtime detection and wire audit and runtime alerts into response playbooks.
- Roll back: keep PSA labels, policies and NetworkPolicies in Git so a breaking change can be reverted to
warnorAuditin one commit while the workload is fixed.
Decision guidance
- PSA alone vs a policy engine: PSA covers pod security fields. Add ValidatingAdmissionPolicy for simple in-process rules and a webhook engine for mutation, signature verification or policy reports. Webhooks with
failurePolicy: Failblock deployments when down, so run them highly available. - Shared vs dedicated clusters: namespaces suit internal teams of similar trust; untrusted tenants, regulated data or customer code justify sandboxed node pools or separate clusters.
- Managed vs self-managed: managed control planes remove etcd and API server work and suit most organisations; self-managed suits air-gapped or highly customised estates with control plane skills.
- Small organisations: a managed service, PSA Baseline everywhere, default-deny policies, provider audit logs and a CIS scan cover most risk. Large organisations: GitOps for RBAC and policy, a central policy library, signature-enforced admission and fleet-wide runtime detection, often through a CNAPP. See the CNAPP Guide.
Detection and measurement
- Privileged access: number of subjects bound to
cluster-admin, and of roles using wildcards or Secret list or watch. - Pod security coverage: percentage of namespaces enforcing Baseline or Restricted, and count of PSA exemptions.
- Network coverage: percentage of namespaces with a default-deny ingress and egress policy.
- Supply chain: percentage of running pods using a digest-pinned, signature-verified image.
- Benchmark posture: CIS Kubernetes Benchmark pass rate per cluster, trended over time.
- Response: time to triage high-severity audit or runtime alerts, such as new cluster-admin bindings or exec into production pods.
Common failure patterns
- Secrets in manifests and repositories: base64 is not encryption. The Exposed Kubernetes Secrets 2023 case put an SAP artifact repository key with access to 95 million artifacts on GitHub; keep Secrets out of Git or encrypt them with an external store.
- cluster-admin for convenience: CI pipelines, operators and Helm charts granted
cluster-adminbecause scoping was hard, turning one stolen pipeline token into full cluster control. See the CI/CD Pipeline Identity Security Guide. - NetworkPolicy without an enforcing CNI: policies are written and reviewed but the network plugin ignores them.
- PSA enforce switched on without warn first: ReplicaSets silently fail to create pods, the label is removed in a hurry and never restored.
- Audit logs that never leave the cluster: logs written to the control plane disk and rotated away before anyone looks.
Framework mapping
| Control area | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | CIS Controls v8.1 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|---|
| RBAC and least privilege | AC-3, AC-6 | PR.AA-05 | 5.4, 6.8 | A.5.15, A.8.2 |
| Hardened configuration, PSA, benchmarks | CM-6, CM-7 | PR.PS-01 | 4.1 | A.8.9 |
| Encryption of Secrets and etcd | SC-28, SC-8 | PR.DS-01, PR.DS-02 | 3.10, 3.11 | A.8.24 |
| Network policies and segmentation | SC-7 | PR.IR-01 | 12.2, 13.4 | A.8.20, A.8.22 |
| Audit logging and monitoring | AU-2, AU-12, SI-4 | PR.PS-04, DE.CM-09 | 8.2, 8.5 | A.8.15, A.8.16 |
Practitioner checklist
- API server, kubelet and etcd are not reachable from the internet; anonymous auth is disabled and authorisation is
Node,RBAC. - etcd uses mutual TLS with its own CA, and Secrets are encrypted at rest with a KMS v2 provider (or the managed equivalent).
- An audit policy is in place with Secrets at
Metadata, and logs are exported off-cluster to the SIEM. system:mastersis unused after bootstrap,cluster-adminbindings are reviewed monthly and alerted on creation.- No roles use wildcards; Secret list and watch,
escalate,bind,impersonateandnodes/proxyare limited to named administrators. - Aggregation labels on ClusterRoles installed by charts and operators are reviewed before install.
- Every namespace has PSA labels, enforcing at least Baseline, with Restricted where workloads allow.
- Admission policy restricts registries and verifies signatures, with digests pinned.
- Every namespace has default-deny ingress and egress NetworkPolicies, enforced by the CNI, and metadata API access is filtered.
- Service account token automounting is off unless needed, as set out in the Kubernetes NHI Security Guide.
Standards and references
- NSA and CISA: Kubernetes Hardening Guide v1.2
- Kubernetes: Security Checklist
- Kubernetes: Role Based Access Control Good Practices
- Kubernetes: Pod Security Standards
- Kubernetes: Encrypting Confidential Data at Rest
- CIS: Kubernetes Benchmark
- MITRE ATT&CK: Containers Matrix
- Microsoft: Threat Matrix for Kubernetes
Related NHI Mgmt Group resources: Kubernetes NHI Security Guide · Cloud Workload Identity Guide · Network Segmentation Guide · CNAPP Guide · SLSA and Build Provenance Guide