Comprehensive guide to hardening Kubernetes clusters covering RBAC, Pod Security Standards, NetworkPolicies, secrets management, audit logging, and image policies.
Kubernetes Attack Surface
Out-of-the-box Kubernetes isn’t secure. The cluster exposes multiple attack vectors that need systematic attention:
API Server - Central control point; unauthorized access = full cluster compromise
etcd - Stores all cluster state including secrets in base64 (not encrypted by default)
Kubelet - Node agent; exposed kubelet API leaks pod info and allows command execution
Container runtime - Breakout vulnerabilities give host access
Network - Pods can communicate freely with any other pod by default
Supply chain - Malicious or vulnerable images introduce backdoors
This guide covers the key hardening measures organized by attack vector.
API Server Hardening
The API server is the most critical component. Secure it first:
Disable anonymous authentication: set --anonymous-auth=false
Enable audit logging: track who did what (covered in detail below)
Restrict access: use firewall rules or security groups to limit who can reach the API server
Enable admission controllers: PodSecurity, NodeRestriction, ResourceQuota, and LimitRanger should all be active
Use OIDC for authentication: integrate with your identity provider instead of relying on client certificates
1
2
# Check current API server flags (on kubeadm clusters)kubectl -n kube-system get pod kube-apiserver-<node> -o jsonpath='{.spec.containers[0].command}'| tr ',''\n'
RBAC Best Practices
RBAC is your primary authorization mechanism. Enforce least privilege rigorously.
Key Rules
Never use cluster-admin for workloads – it grants unlimited access
Use Roles (namespaced) over ClusterRoles whenever possible
Avoid wildcards in resource or verb specifications
Bind to ServiceAccounts, not users for automated workloads
Review bindings regularly – permissions accumulate over time
apiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:namespace:productionname:deployment-managerrules:# Can manage deployments- apiGroups:["apps"]resources:["deployments"]verbs:["get","list","watch","create","update","patch"]# Can view pods and logs- apiGroups:[""]resources:["pods","pods/log"]verbs:["get","list","watch"]# Can view services- apiGroups:[""]resources:["services"]verbs:["get","list","watch"]# Explicitly NO access to secrets, configmaps/write, or exec---apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:namespace:productionname:deployment-manager-bindingsubjects:- kind:ServiceAccountname:ci-deployernamespace:productionroleRef:kind:Rolename:deployment-managerapiGroup:rbac.authorization.k8s.io
Audit existing RBAC with:
1
2
3
4
5
6
# List all cluster-admin bindingskubectl get clusterrolebindings -o json |\
jq '.items[] | select(.roleRef.name == "cluster-admin") | {name: .metadata.name, subjects: .subjects}'# Check what a specific service account can dokubectl auth can-i --list --as=system:serviceaccount:production:ci-deployer -n production
Pod Security Standards
Kubernetes Pod Security Standards (PSS) define three security restriction levels. Since 1.25, Pod Security Admission (PSA) is the built-in enforcement mechanism (replaces PodSecurityPolicy).
The Three Levels
Level
Description
Use Case
Privileged
No restrictions
System-level workloads (CNI, storage drivers)
Baseline
Blocks known privilege escalations
General-purpose workloads
Restricted
Maximum hardening
Sensitive workloads, multi-tenant clusters
Enforcing Pod Security Standards
Apply standards at the namespace level using labels:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion:v1kind:Namespacemetadata:name:productionlabels:# Enforce restricted: reject pods that violatepod-security.kubernetes.io/enforce:restrictedpod-security.kubernetes.io/enforce-version:latest# Warn on baseline violations (shows warning but allows)pod-security.kubernetes.io/warn:restrictedpod-security.kubernetes.io/warn-version:latest# Audit: log violationspod-security.kubernetes.io/audit:restrictedpod-security.kubernetes.io/audit-version:latest
Note: NetworkPolicies require a CNI plugin that supports them (Calico, Cilium, Weave Net). The default kubenet does not enforce NetworkPolicies.
Secrets Management
Kubernetes Secrets are base64-encoded, not encrypted. Anyone with read access to Secrets in a namespace can decode them trivially. Proper secrets management requires additional tooling.
Option 1: Sealed Secrets
Sealed Secrets (by Bitnami) encrypts secrets client-side so they can be safely stored in Git:
1
2
3
4
5
6
7
8
9
10
# Install kubeseal CLI# Encrypt a secretkubectl create secret generic db-creds \
--from-literal=password=supersecret \
--dry-run=client -o yaml |\
kubeseal --format yaml > sealed-db-creds.yaml
# The sealed secret can be committed to Git# Only the cluster's controller can decrypt itkubectl apply -f sealed-db-creds.yaml
Option 2: External Secrets Operator
External Secrets Operator syncs secrets from external providers (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) into Kubernetes:
# audit-policy.yamlapiVersion:audit.k8s.io/v1kind:Policyrules:# Log all requests to secrets at the Metadata level- level:Metadataresources:- group:""resources:["secrets"]# Log pod exec/attach at RequestResponse level- level:RequestResponseresources:- group:""resources:["pods/exec","pods/attach"]# Log all write operations at Request level- level:Requestverbs:["create","update","patch","delete"]# Log everything else at Metadata level- level:MetadataomitStages:- RequestReceived
Ship audit logs to your SIEM or log aggregation system (Loki, Elasticsearch) for analysis and alerting.
Image Policies with Kyverno
Kyverno is a policy engine for Kubernetes that validates, mutates, and generates resources based on policies. It is simpler to adopt than OPA Gatekeeper because policies are written as Kubernetes resources rather than Rego.
apiVersion:kyverno.io/v1kind:ClusterPolicymetadata:name:require-image-digestspec:validationFailureAction:Enforcerules:- name:require-digestmatch:any:- resources:kinds:- Podvalidate:message:"Images must use a digest (@sha256:...) instead of a tag"pattern:spec:containers:- image:"*@sha256:*"- name:require-trusted-registrymatch:any:- resources:kinds:- Podvalidate:message:"Images must come from the trusted registry"pattern:spec:containers:- image:"myregistry.com/*"
This policy ensures that only images from your trusted registry with pinned digests are deployed, preventing both supply chain attacks and tag mutability issues.
CIS Kubernetes Benchmark
The CIS Kubernetes Benchmark provides a comprehensive set of security recommendations. Run automated checks with kube-bench:
Address findings by priority: critical items first (API server auth, etcd encryption), then high (RBAC, network policies), then medium and low.
Hardening Checklist
Use this checklist as a starting point for securing your cluster:
API server: anonymous auth disabled, audit logging enabled
etcd: encrypted at rest, access restricted to API server only
RBAC: no unnecessary cluster-admin bindings, least privilege enforced
Pod Security: restricted PSS enforced on production namespaces
NetworkPolicies: default deny in all namespaces, explicit allow rules
Secrets: external secrets manager or sealed secrets, encryption at rest
Images: signed images, trusted registry enforcement, digest pinning
Nodes: automatic security updates, CIS-hardened OS
Audit: API server audit logs shipped to SIEM
Monitoring: alerts on RBAC changes, privileged pod creation, exec into pods
Supply chain: vulnerability scanning in CI/CD, admission-time image scanning
Network: TLS between all components, service mesh for mTLS between pods
Security hardening is not a one-time activity. Schedule quarterly reviews to reassess your posture, run CIS benchmarks, review RBAC bindings, and update policies as your cluster evolves.