Kubernetes has become the de facto standard for container orchestration, but its complexity introduces a wide attack surface that many teams underestimate. Misconfigurations in RBAC policies, exposed API servers, privileged containers running unchecked, and absent network policies are responsible for a significant portion of cloud-native breaches. Hardening your cluster from the moment it is provisioned is not optional; it is the baseline expectation for any production-grade deployment.
This guide walks through the most critical Kubernetes security best practices with real commands, working configurations, and the reasoning behind each control. Whether you are standing up a new cluster or auditing an existing one, these practices apply.
Unlike traditional VM-based infrastructure, Kubernetes introduces layers of abstraction: the control plane, the kubelet, the container runtime, and the workloads themselves. Each layer has its own attack surface. A misconfigured admission controller, a wildcard RBAC binding, or an unencrypted secret can be exploited by an attacker who has already gained a foothold inside the cluster.
The 2023 NSA/CISA Kubernetes Hardening Guide emphasized that default Kubernetes configurations are often insecure and that operators must actively configure each layer rather than relying on defaults. If your team needs a structured approach to assessing your current posture, the Redfox Cybersecurity cloud and infrastructure security services can provide a thorough cluster audit before you harden in production.
The API server is the central control point for your entire cluster. Exposing it incorrectly is one of the most common and dangerous misconfigurations.
By default, some distributions allow unauthenticated requests to reach the API server. Disable this immediately.
kube-apiserver \
--anonymous-auth=false \
--authorization-mode=Node,RBAC \
--enable-admission-plugins=NodeRestriction,PodSecurity \
--tls-cert-file=/etc/kubernetes/pki/apiserver.crt \
--tls-private-key-file=/etc/kubernetes/pki/apiserver.key \
--client-ca-file=/etc/kubernetes/pki/ca.crt \
--audit-log-path=/var/log/kubernetes/audit.log \
--audit-log-maxage=30 \
--audit-log-maxbackup=10 \
--audit-log-maxsize=100
[cta]
The API server should never be exposed to the public internet. Use firewall rules and, where possible, a private endpoint.
# Example: restrict API server to a specific CIDR using iptables
iptables -A INPUT -p tcp --dport 6443 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 6443 -j DROP
[cta]
Use cloud provider-native controls as well. On AWS EKS, for example, set your cluster endpoint access to private and allowlist specific CIDRs:
aws eks update-cluster-config \
--name my-cluster \
--resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true
[cta]
Role-Based Access Control is the primary authorization mechanism in Kubernetes, but poorly designed RBAC is one of the most exploited weaknesses in cloud-native environments.
Before applying new policies, audit what you already have. Tools like kubectl-who-can and rbac-tool from Aqua Security provide fast visibility.
# Install rbac-tool
kubectl krew install rbac-tool
# Check who can create pods in the default namespace
kubectl rbac-tool who-can create pods -n default
# Check all bindings across the cluster
kubectl rbac-tool policy-rules -n "" | grep -i "secrets\|exec\|create"
[cta]
A service account bound to cluster-admin gives any compromised pod full control of the cluster. Create scoped roles instead.
# Scoped role: read-only access to pods in a specific namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: production
subjects:
- kind: ServiceAccount
name: monitoring-agent
namespace: production
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
[cta]
By default, Kubernetes mounts service account tokens into every pod. If the workload does not need API access, disable this.
apiVersion: v1
kind: ServiceAccount
metadata:
name: restricted-sa
namespace: production
automountServiceAccountToken: false
[cta]
If you need support designing a least-privilege RBAC architecture for a large multi-tenant cluster, the team at Redfox Cybersecurity regularly helps organizations build role hierarchies that hold up under real adversarial pressure.
Privileged pods running as root with host path mounts are a frequent path from container escape to full node compromise.
Kubernetes 1.25 and later ships Pod Security Admission as the built-in replacement for PodSecurityPolicy. Apply the restricted standard to your namespaces.
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
[cta]
Every pod spec should explicitly configure security context settings. Do not rely on defaults.
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: production
spec:
securityContext:
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: my-registry/secure-app:1.0.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
[cta]
Use Trivy or Grype to scan container images in your CI pipeline before they are promoted.
# Trivy scan with severity filtering
trivy image --severity HIGH,CRITICAL --exit-code 1 my-registry/secure-app:1.0.0
# Grype scan with SARIF output for SIEM integration
grype my-registry/secure-app:1.0.0 -o sarif > results.sarif
[cta]
Integrating image scanning into your pipeline is a control that pays dividends immediately. If your team is building a DevSecOps pipeline from scratch and wants expert review, Redfox Cybersecurity's application security services cover the full CI/CD hardening lifecycle.
By default, all pods in a Kubernetes cluster can communicate with all other pods. This flat network model is dangerous in multi-tenant or production environments.
Start with a default deny for all ingress and egress in sensitive namespaces, then explicitly allow what is needed.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
[cta]
After establishing a default deny baseline, layer in targeted allow rules.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
role: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 8080
[cta]
Declaring a NetworkPolicy is not enough. Verify that your CNI plugin is actually enforcing it.
# Using netassert to test network reachability
cat <<EOF | netassert -
- from: pod/production/frontend
to: pod/production/backend
port: 8080
allowed: true
- from: pod/production/frontend
to: pod/production/database
port: 5432
allowed: false
EOF
[cta]
Kubernetes Secrets are base64-encoded, not encrypted, by default. Any attacker with access to etcd has access to every secret in your cluster.
Configure the API server to encrypt secret data before writing it to etcd.
# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
[cta]
Then reference the file in your API server configuration:
kube-apiserver \
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
[cta]
For production workloads, use the External Secrets Operator to pull credentials from HashiCorp Vault, AWS Secrets Manager, or GCP Secret Manager at runtime.
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: secret/production/database
property: password
[cta]
Static hardening is necessary but not sufficient. You need to detect malicious activity as it happens.
A minimal audit policy that catches privilege escalation, secret access, and exec events:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["secrets", "serviceaccounts/token"]
- level: RequestResponse
verbs: ["create", "delete", "patch"]
resources:
- group: "rbac.authorization.k8s.io"
resources: ["clusterrolebindings", "rolebindings"]
- level: RequestResponse
verbs: ["create"]
resources:
- group: ""
resources: ["pods/exec", "pods/attach"]
- level: Metadata
omitStages:
- RequestReceived
[cta]
Falco monitors kernel-level syscalls and Kubernetes audit events to detect container escapes, unexpected privilege use, and lateral movement.
# Install Falco via Helm
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace \
--set falco.grpc.enabled=true \
--set falco.grpcOutput.enabled=true \
--set auditLog.enabled=true
[cta]
A critical Falco rule example that detects shell execution inside a container:
- rule: Terminal shell in container
desc: A shell was used as the entrypoint or exec'd into a container
condition: >
spawned_process and container
and shell_procs and proc.tty != 0
and not container.image.repository in (allowed_shell_images)
output: >
Shell spawned in a container (user=%user.name container=%container.name
image=%container.image.repository shell=%proc.name parent=%proc.pname
cmdline=%proc.cmdline)
priority: WARNING
tags: [container, shell, mitre_execution]
[cta]
Teams that want continuous runtime monitoring as a managed service rather than self-operated tooling can explore Redfox Cybersecurity's managed security services for cloud-native environments.
Software supply chain attacks targeting container registries and Helm charts are increasing. Admission controllers can gate what actually runs.
Sigstore's Cosign plus Kyverno creates an enforcement layer that rejects unsigned images at admission time.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signatures
spec:
validationFailureAction: Enforce
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "my-registry.io/production/*"
attestors:
- count: 1
entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
<your-cosign-public-key>
-----END PUBLIC KEY-----
[cta]
kube-bench from Aqua Security tests your cluster against the CIS Kubernetes Benchmark automatically.
# Run kube-bench as a Kubernetes Job
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
# Retrieve results
kubectl logs job/kube-bench
[cta]
A sample output section you want to see all pass:
[PASS] 1.2.1 Ensure that the --anonymous-auth argument is set to false
[PASS] 1.2.6 Ensure that the --authorization-mode argument is not set to AlwaysAllow
[FAIL] 1.2.22 Ensure that the --audit-log-path argument is set
[WARN] 1.2.23 Ensure that the --audit-log-maxage argument is set to 30 or as appropriate
[cta]
Each [FAIL] or [WARN] line is an actionable remediation item. Running this at cluster provisioning and on a recurring schedule as part of your compliance program closes the gap between initial hardening and configuration drift over time.
Kubernetes security is not a single control or a one-time audit. It is a layered discipline that spans the control plane, workloads, networking, secrets, runtime behaviour, and supply chain integrity. The practices covered here represent the baseline every production cluster should meet before workloads go live.
To summarize the core areas:
restricted level, enforce non-root execution, drop all capabilities, and use read-only root filesystems.Hardening a Kubernetes cluster correctly requires both deep platform knowledge and a clear threat model. If your organization is deploying Kubernetes at scale and needs an independent assessment of your current posture, the security engineers at Redfox Cybersecurity bring hands-on experience with real-world cluster compromise scenarios to help you build defenses that hold.