Kubernetes has become the de facto standard for container orchestration, but its flexibility comes with security complexity. A misconfigured cluster can expose your entire infrastructure to attackers. This guide covers the essential security practices for running Kubernetes in production.
The Kubernetes Attack Surface
Before implementing security controls, understand what you're protecting:
- API Server: The gateway to your cluster - if compromised, attackers control everything
- etcd: Stores all cluster state including secrets - a prime target
- Kubelet: Runs on every node and can execute arbitrary containers
- Container Runtime: A container escape gives access to the host
- Network: By default, all pods can communicate with each other
1. Cluster Hardening
Secure the API Server
- Never expose the API server to the public internet
- Use private endpoints (EKS private cluster, GKE private cluster)
- Enable audit logging for all API requests
- Restrict API access using authorized networks
Protect etcd
etcd contains all cluster secrets and configuration:
- Enable encryption at rest for etcd data
- Use TLS for etcd peer and client communication
- Restrict network access to etcd (control plane only)
- Regular backups with encryption
Enable Audit Logging
# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all requests to secrets
- level: Metadata
resources:
- group: ""
resources: ["secrets"]
# Log pod exec/attach/portforward
- level: Request
resources:
- group: ""
resources: ["pods/exec", "pods/attach", "pods/portforward"]
# Log all other requests at metadata level
- level: Metadata
2. Authentication and Authorization
Use OIDC for User Authentication
Never use static tokens or basic auth. Integrate with your identity provider:
- Configure OIDC authentication with your IdP (Okta, Azure AD, Google)
- Use short-lived tokens with automatic refresh
- Implement MFA at the IdP level
Implement RBAC Properly
Follow least privilege principles with Role-Based Access Control:
# Namespace-scoped role for developers
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: my-app
rules:
- apiGroups: [""]
resources: ["pods", "pods/log", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
---
# Bind role to group from OIDC
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: my-app
subjects:
- kind: Group
name: "developers" # From OIDC groups claim
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
Avoid Dangerous RBAC Permissions
These permissions can lead to privilege escalation:
*on any resource (wildcard verbs)createon pods, deployments (can run arbitrary code)createon roles/rolebindings (can grant themselves more permissions)execon pods (shell access to containers)geton secrets (access to credentials)
3. Pod Security
Use Pod Security Standards
Kubernetes 1.25+ uses Pod Security Admission to enforce security standards:
# Enforce restricted standard on namespace
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Never Run as Root
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
Use Read-Only Root Filesystem
Prevent attackers from writing malicious files:
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
Drop All Capabilities
Linux capabilities grant specific privileges. Drop all and add only what's needed:
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # Only if binding to ports < 1024
4. Network Security
Implement Network Policies
By default, all pods can communicate. Use NetworkPolicies to restrict traffic:
# Default deny all ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
---
# Allow frontend to talk to backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Use a Service Mesh for mTLS
Service meshes like Istio or Linkerd provide automatic mTLS between pods:
- Encrypt all pod-to-pod traffic
- Strong identity for each workload
- Fine-grained authorization policies
- Traffic observability
5. Secrets Management
Don't Use Kubernetes Secrets Alone
Kubernetes secrets are base64 encoded, not encrypted. Enhance security with:
Enable Encryption at Rest
# EncryptionConfiguration
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret:
- identity: {}
Use External Secrets Operators
Sync secrets from external providers like AWS Secrets Manager, HashiCorp Vault, or Azure Key Vault:
# ExternalSecret syncs from AWS Secrets Manager
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: db-credentials
data:
- secretKey: password
remoteRef:
key: production/database
property: password
Use Workload Identity
Avoid storing cloud credentials in secrets. Use workload identity to let pods assume cloud IAM roles:
- EKS: IAM Roles for Service Accounts (IRSA)
- GKE: Workload Identity
- AKS: Azure AD Workload Identity
6. Image Security
Scan Images for Vulnerabilities
Integrate scanning into your CI/CD pipeline:
# Example: Trivy scan in CI
trivy image --severity HIGH,CRITICAL \
--exit-code 1 \
my-registry/my-app:latest
Use Signed Images
Implement image signing and verification with Sigstore/Cosign:
# Sign image
cosign sign --key cosign.key my-registry/my-app:latest
# Verify in admission controller
# Kyverno policy example
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: enforce
rules:
- name: verify-signature
match:
resources:
kinds:
- Pod
verifyImages:
- image: "my-registry/*"
key: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Use Minimal Base Images
Reduce attack surface with distroless or scratch images:
# Distroless image
FROM gcr.io/distroless/static-debian11
COPY --from=builder /app/binary /app/binary
ENTRYPOINT ["/app/binary"]
7. Runtime Security
Deploy Runtime Protection
Use tools like Falco to detect suspicious runtime behavior:
# Falco rule: Detect shell in container
- rule: Shell Spawned in Container
desc: Detect shell being spawned in a container
condition: >
spawned_process and container and
shell_procs and not shell_allowed
output: >
Shell spawned in container
(user=%user.name container=%container.name
shell=%proc.name parent=%proc.pname)
priority: WARNING
Common Runtime Detections
- Shell spawned in container
- Sensitive file access (/etc/shadow, /etc/passwd)
- Network tools executed (curl, wget, nc)
- Crypto mining processes
- Container escape attempts
8. Supply Chain Security
Pin Image Digests
Don't use mutable tags like latest. Pin to immutable digests:
# Bad: Tag can be overwritten
image: nginx:1.21
# Good: Immutable digest
image: nginx@sha256:abc123...
Use Private Registries
- Mirror public images to your private registry
- Scan images before allowing them in your registry
- Implement registry access controls
Security Checklist
Quick reference for Kubernetes security hardening:
- API server not exposed publicly
- RBAC enabled with least privilege
- Pod Security Standards enforced
- Network policies implemented (default deny)
- Secrets encrypted at rest
- External secrets manager integrated
- Workload identity configured (no static cloud credentials)
- Image scanning in CI/CD
- Image signing and verification
- Runtime protection deployed
- Audit logging enabled
- Containers running as non-root
- Read-only root filesystem where possible
- All capabilities dropped
Next Steps
Kubernetes security requires continuous attention. Start with the fundamentals - RBAC, pod security, and network policies - then layer on advanced protections like runtime security and supply chain controls.
Need help securing your Kubernetes clusters? Contact us for expert guidance on implementing these best practices.