| name | kubernetes-security |
| description | Harden Kubernetes clusters with RBAC, pod security, network policies, and supply chain controls. Outputs security baseline, admission policies, audit configuration, and hardening checklist. |
| argument-hint | ["cluster type","workload sensitivity","compliance requirements","multi-tenancy needs"] |
| allowed-tools | Read, Write |
Kubernetes Security
Kubernetes has a large attack surface — misconfigured RBAC, privileged pods, and exposed API servers are common breach vectors. A secure cluster implements defence-in-depth: restrict who can do what (RBAC), restrict what containers can do (Pod Security), restrict network traffic (NetworkPolicy), and detect anomalies (audit logging + Falco).
RBAC Least Privilege
kind: ClusterRole
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: order-service-role
namespace: production
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["db-credentials", "api-keys"]
verbs: ["get"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: order-service-binding
namespace: production
subjects:
- kind: ServiceAccount
name: order-service
namespace: production
roleRef:
kind: Role
name: order-service-role
apiGroup: rbac.authorization.k8s.io
Pod Security Standards
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
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
serviceAccountName: order-service
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: api
image: myapp:v1.2.3@sha256:abc123
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem:
[]
{ , }
{ , }
{}
Kyverno Security Policies
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce
rules:
- name: check-image-tag
match:
any:
- resources:
kinds: [Pod]
namespaces: [production, staging]
validate:
message: "Use a specific image tag or digest, not 'latest'"
pattern:
spec:
containers:
- image: "!*:latest"
---
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-resource-limits
spec:
validationFailureAction: Enforce
rules:
- name: check-limits
match:
any:
- resources: { []}
Audit Logging
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
resources:
- group: ""
resources: [secrets, configmaps]
- group: "rbac.authorization.k8s.io"
resources: [roles, clusterroles, rolebindings, clusterrolebindings]
- level: Metadata
resources:
- group: ""
resources: [pods, pods/exec, pods/portforward]
- level: None
users: [system:kube-scheduler, system:kube-controller-manager]
verbs: [get, list, watch]
resources:
- group: ""
resources: [, , ]
Hardening Checklist
API Server
[ ] Anonymous auth disabled (--anonymous-auth=false)
[ ] Audit logging enabled
[ ] --authorization-mode=Node,RBAC (not AlwaysAllow)
[ ] --enable-admission-plugins includes PodSecurity
RBAC
[ ] No wildcard permissions in production
[ ] Service accounts have minimal permissions
[ ] Cluster-admin binding count minimised (audit quarterly)
[ ] automountServiceAccountToken=false unless needed
Workloads
[ ] All pods: runAsNonRoot, readOnlyRootFilesystem
[ ] All pods: capabilities dropped, no privilege escalation
[ ] All pods: resource limits set
[ ] All pods: seccomp profile RuntimeDefault or custom
[ ] Images pinned to digest (not :latest)
Network
[ ] Default-deny NetworkPolicy in all namespaces
[ ] Ingress restricted to known sources
[ ] Egress restricted to required destinations
Secrets
[ ] Secrets encrypted at rest (etcd encryption)
[ ] No secrets in environment variables — use volume mounts
[ ] External secrets operator for secrets manager integration
Anti-Patterns to Avoid
| Anti-Pattern | Problem | Fix |
|---|
| Cluster-admin for app service accounts | App compromise = cluster compromise | Minimum RBAC for each service account |
| Running as root | Container escape easier from root | runAsNonRoot: true + fixed UID |
| Latest image tag | Unexpected updates; no reproducibility | Pin to digest: image@sha256:... |
| No audit logging | Security incidents undetectable | Audit policy + centralised log shipping |
| Privileged containers | Full host access | Never privileged: true in production |
10 Rules
- Every pod runs as non-root with a fixed UID — no exceptions in production.
- Service accounts have only the permissions they need — no wildcard RBAC.
- Images are pinned to digest — tags are mutable; digests are not.
- Audit logging enabled for secrets, RBAC changes, and pod exec — these are your incident trail.
- Default-deny NetworkPolicy in every production namespace.
- Resource limits on every container — no limits = noisy neighbour risk.
readOnlyRootFilesystem: true — writable filesystems allow persistence of malicious payloads.
- Admission controllers (Kyverno/OPA) enforce policies at deploy time — not just at audit.
- Rotate service account tokens regularly — use projected volumes with short TTL.
- Run CIS Benchmark scans quarterly —
kube-bench reports regressions in cluster hardening.