A Practical Kubernetes Security Hardening Checklist
Free DevOps Audit Checklist
Get our comprehensive checklist to identify gaps in your infrastructure, security, and deployment processes
Why a Default Cluster Is Not Secure
A freshly provisioned Kubernetes cluster prioritizes getting workloads running, not locking them down. By default, pods can talk to each other freely, service accounts get mounted everywhere, containers can run as root, and there is nothing stopping a compromised pod from reaching the cloud metadata endpoint. Hardening is the work of closing those gaps deliberately. This checklist is organized by the areas that matter most in practice.
RBAC: Least Privilege for Humans and Workloads
Role-Based Access Control is your primary authorization layer. The failure mode is granting cluster-admin to everyone because it makes things work.
- Never bind cluster-admin to users or service accounts outside of break-glass scenarios. Audit existing bindings with
kubectl get clusterrolebindings -o wide. - Scope roles to namespaces with Role and RoleBinding rather than the cluster-wide variants wherever possible.
- Avoid wildcard verbs and resources. A role with
verbs: ["*"]onresources: ["*"]is cluster-admin in disguise. - Disable automounting of service account tokens where pods do not call the API server: set
automountServiceAccountToken: falseon the service account or pod spec. - Give each workload its own service account so you can scope and revoke access per application, not per namespace default.
Need DevOps help?
InstaDevOps provides expert DevOps engineering starting at $2,999/mo. Skip the hiring headache.
Book a free 15-min call →Network Policies: Default Deny
Without network policies, every pod can reach every other pod. Flip this to default-deny and explicitly allow required traffic. Note that you need a CNI that enforces policies (Calico, Cilium, or similar); some managed defaults do not enforce them.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressThen add allow rules per service. Pay particular attention to egress: blocking egress to the cloud metadata IP (169.254.169.254) stops a compromised pod from stealing node IAM credentials, one of the most common cluster escape paths.
Pod Security: Constrain the Runtime
Pod Security Standards replaced the deprecated PodSecurityPolicy. Enforce the restricted profile via the built-in Pod Security Admission controller by labeling namespaces:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/warn: restrictedAt the pod and container level, apply these settings:
- runAsNonRoot: true and a specific non-zero
runAsUser. - readOnlyRootFilesystem: true, mounting writable emptyDir volumes only where needed.
- allowPrivilegeEscalation: false and privileged: false.
- Drop all Linux capabilities with
capabilities: {drop: ["ALL"]}and add back only what a workload truly needs. - Set resource requests and limits so a single pod cannot exhaust node CPU or memory and cause a denial of service.
Secrets: Stop Storing Them in Plaintext
Kubernetes Secrets are only base64-encoded, not encrypted, and by default they sit in etcd in plaintext. Harden this:
- Enable encryption at rest for etcd using a KMS provider so secrets are encrypted with a managed key.
- Prefer an external secrets manager (AWS Secrets Manager, Vault) synced via the External Secrets Operator, so the source of truth lives outside the cluster.
- Restrict secret access with RBAC: very few roles should be able to
getorlistsecrets. - Never bake secrets into images or commit them to git. Scan repos and images for leaked credentials as part of CI.
- Rotate regularly and treat any secret that has touched a log or a git history as compromised.
Supply Chain: Trust What You Run
A hardened runtime does not help if you deploy a backdoored image. Secure the path from source to running container.
- Scan images for vulnerabilities in CI with Trivy or Grype, and fail the build on fixable critical CVEs.
- Use minimal base images (distroless or Alpine) to shrink the attack surface and CVE count.
- Pin images by digest, not by mutable tags like
latest, so you always run exactly what you scanned. - Sign images and verify signatures with Cosign, enforced by an admission controller so unsigned images cannot deploy.
- Use an admission policy engine (Kyverno or OPA Gatekeeper) to reject pods that violate policy: no privileged containers, no
latesttags, required labels, approved registries only. - Generate an SBOM for each image so you can answer "are we affected?" fast when the next big CVE drops.
Runtime Threat Detection
Prevention controls reduce your attack surface, but you also need to know when something slips through. Add a detection layer so a compromise is caught in minutes, not months:
- Deploy a runtime security agent such as Falco or a comparable eBPF-based tool. It watches syscalls and flags suspicious behavior: a shell spawned inside a container, an unexpected outbound connection, or a write to a sensitive path.
- Alert on privilege escalation attempts and on any process reading service account tokens it should not touch.
- Monitor for crypto-mining signatures, the most common outcome of a compromised cluster exposed to the internet.
- Centralize and retain audit and runtime logs so you can reconstruct an incident timeline. Detection is only useful if you can investigate what happened afterward.
Cluster and Control Plane Hygiene
- Keep the Kubernetes version current; end-of-life versions stop getting security patches.
- Enable and ship audit logs to a central store so you can investigate suspicious API activity.
- Restrict access to the API server; do not expose it to the public internet without tight controls.
- Run the CIS Kubernetes Benchmark with kube-bench and remediate the failures it reports.
- Isolate workloads by sensitivity using separate namespaces or node pools.
Treat this list as a baseline you enforce continuously with policy-as-code, not a one-time cleanup. The cheapest time to add these controls is before an incident, and the hardest audit finding to explain is the one you knew about. Teams running production clusters usually fold this into managed Kubernetes so hardening is maintained rather than bolted on later, and pair it with broader DevOps as a service coverage.
Hardening a live cluster without breaking workloads takes experience, and the failure modes are unforgiving. If you want senior engineers to audit your cluster against this checklist and implement the fixes safely, InstaDevOps provides a senior DevOps engineer on retainer (Startup $2,999/mo, Business $4,999/mo) with a typical response time around 48 hours. Book a 15-minute call to review your Kubernetes security posture.
Ready to Transform Your DevOps?
Get started with InstaDevOps and experience world-class DevOps services.
Book a Free CallNever Miss an Update
Get the latest DevOps insights, tutorials, and best practices delivered straight to your inbox. Join 500+ engineers leveling up their DevOps skills.