Why your cluster is probably misconfigured
The majority of Kubernetes security incidents trace back to three root causes: overly permissive RBAC, workloads running as root, and secrets stored as plain environment variables. The Kubernetes default configuration is optimised for flexibility, not security. Hardening requires deliberate choices at every layer.
Identity & Access
kubectl auth can-i --list --as=system:serviceaccount:ns:sa to audit what each SA can do.cluster-admin, that is a red flag requiring architectural review, not a rubber-stamp approval.automountServiceAccountToken: false on all pods that do not need Kubernetes API access.Workload Security
restricted profile on production namespaces using the built-in Pod Security Admission controller. This blocks privileged containers, host path mounts, and root execution by default.runAsNonRoot: true and runAsUser: 1000 in your security context. Most application containers do not need root. Those that claim to do should be investigated.readOnlyRootFilesystem: true prevents attackers from writing malware to disk after a container escape. Mount writable volumes only where needed (e.g., /tmp).capabilities: drop: [ALL] and add back only what you need (NET_BIND_SERVICE for port 80/443, nothing else for most workloads).Network Policies
By default, all pods can talk to all pods. Network policies are your firewall inside the cluster. Every namespace should have a default-deny ingress and egress policy, with explicit allow rules for each required communication path:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
Then add specific allow policies. A service that only needs to receive traffic from the ingress controller and talk to the database should have exactly two policies β nothing more.
Secrets Management
Image Security
europe-west1-docker.pkg.dev/my-project/*) can run in production namespaces. Block :latest tags.Runtime Security
Falco is the open-source standard for Kubernetes runtime threat detection. It monitors syscalls and generates alerts when a process deviates from expected behaviour β for example, a web server spawning a shell or reading /etc/shadow:
- rule: Terminal shell in container
desc: A shell was spawned inside a container
condition: >
container and
shell_procs and
proc.name in (shell_binaries) and
k8s.pod.name != ""
output: >
Shell opened in container (user=%user.name
container=%container.name pod=%k8s.pod.name)
priority: WARNING
Connect Falco alerts to your SIEM or PagerDuty. A shell spawning in a production container at 03:00 UTC is worth waking someone up for.
Audit Logging
Enable API server audit logging with a policy that captures all requests at the RequestResponse level for sensitive resources (Secrets, RBAC, ServiceAccounts) and Metadata for everything else. Ship logs to your SIEM within 5 minutes. Retention: 90 days minimum for compliance.
The bottom line
Security hardening is not a one-time task β it is an ongoing posture. Run a quarterly RBAC audit, update your Falco rules when you add new workloads, and re-scan images on a schedule even if they have not changed (new CVEs are disclosed daily). The clusters that get compromised are rarely the ones attacked by sophisticated actors β they are the ones that never closed the basics.