The Insecure Defaults Problem

A default Kubernetes installation allows pods to run as root, access the host network, mount arbitrary host paths, and communicate with any other pod in the cluster. The API server's default service account token is mounted in every pod β€” giving any compromised container direct API access.

The CIS Kubernetes Benchmark documents over 100 security checks. A fresh cluster typically fails 40-60% of them. This isn't a criticism of Kubernetes β€” it's a trade-off made deliberately to favour developer experience over security by default.

Real consequence: The 2020 Tesla cryptojacking incident and numerous cryptocurrency exchange breaches originated from exposed Kubernetes dashboards and misconfigured RBAC. Container escape via privileged pods is a documented, actively exploited attack path.

RBAC: Enforce Least Privilege

Role-Based Access Control (RBAC) is Kubernetes' primary authorization mechanism. Common mistakes: giving workloads cluster-admin, using wildcard verbs (*), and not binding service accounts to least-privilege roles.

rbac-least-privilege.yaml YAML
# Minimal role: read-only access to pods in one namespace
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
  # NOT "create", "delete", "patch", "*"
---
# Disable automatic service account token mounting
apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app
automountServiceAccountToken: false

Audit existing RBAC with kubectl auth can-i --list --as=system:serviceaccount:default:default to see what the default service account can do in each namespace.

Pod Security Standards

Pod Security Standards (PSS) replaced PodSecurityPolicies in Kubernetes 1.25. Three enforcement levels: Privileged (unrestricted), Baseline (prevents known privilege escalations), and Restricted (security best practices).

namespace-restricted.yaml YAML
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted
---
# Pod spec that passes restricted policy
securityContext:
  runAsNonRoot: true
  runAsUser: 10001
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  seccompProfile:
    type: RuntimeDefault
  capabilities:
    drop: ["ALL"]

Network Policies: Default Deny

By default, all pods in a Kubernetes cluster can communicate with all other pods β€” across namespaces. A compromised pod can reach your database, internal APIs, and cloud metadata endpoints. NetworkPolicies implement microsegmentation.

default-deny-all.yaml YAML
# Step 1: Default deny all ingress and egress in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

NetworkPolicies require a CNI plugin: The default CNI in most clusters doesn't enforce NetworkPolicies. You need Calico, Cilium, or Weave Net. Verify enforcement before trusting your policies.

Secrets Management

Kubernetes Secrets are base64-encoded, not encrypted, by default. Anyone with kubectl get secret access β€” or direct etcd access β€” can read them in plaintext. The two correct approaches:

  • Encrypt at rest: Enable etcd encryption with an AES-CBC or AES-GCM provider in the API server configuration (--encryption-provider-config).
  • External secrets manager: Use HashiCorp Vault, AWS Secrets Manager, or GCP Secret Manager with the External Secrets Operator or Vault Agent Injector. Secrets never live in etcd.

Sealed Secrets: Bitnami Sealed Secrets encrypts secrets with the cluster's public key before they touch git. Only the cluster can decrypt them. Good for GitOps workflows where you need secrets in source control.

Image Scanning and Admission Control

Scanning images in CI catches known CVEs before deployment. But images can change after being scanned β€” you also need admission control to block unscanned or non-compliant images from reaching the cluster.

  • Trivy / Grype: Fast, free image scanners that run in CI pipelines
  • Kyverno / OPA Gatekeeper: Policy engines that enforce image scanning results and signing requirements at admission time
  • Cosign / Sigstore: Sign images in CI, verify signatures in admission controllers β€” prevents image tampering after push

API Server Hardening

  • Disable anonymous authentication: --anonymous-auth=false
  • Enable audit logging: --audit-log-path and --audit-policy-file
  • Restrict --authorization-mode to RBAC and Node only (remove AlwaysAllow)
  • Disable the insecure port: --insecure-port=0 (default in 1.20+)
  • Use TLS for etcd communication and client certificate auth

Runtime Protection

Static analysis catches misconfigurations before deployment. Runtime protection detects anomalous behaviour after a breach. Falco is the CNCF-graduated runtime security tool β€” it uses eBPF to monitor system calls and alert on suspicious activity: unexpected outbound connections, privilege escalation, reading /etc/shadow.

Kubernetes Security Checklist

  1. RBAC: no wildcard verbs, no unnecessary cluster-admin, automountServiceAccountToken disabled
  2. Pod Security Standards: Restricted policy on production namespaces
  3. All containers run as non-root with readOnlyRootFilesystem and no capabilities
  4. NetworkPolicies: default-deny-all, explicit allow rules per workload
  5. etcd encrypted at rest or secrets in external manager (Vault, AWS Secrets Manager)
  6. Images scanned in CI, signatures verified at admission
  7. API server audit logging enabled and shipped to SIEM
  8. Falco or equivalent runtime detection deployed
  9. CIS Kubernetes Benchmark run quarterly (kube-bench)

Scan Your Kubernetes Manifests

AquilaX IaC scanning detects misconfigurations in Kubernetes manifests β€” overprivileged pods, missing security contexts, exposed secrets β€” before they reach your cluster.

Start Free Scan