Cloud Native 39 min read

From a Compromised Pod to Enterprise‑Grade Kubernetes Security: A Deep‑Defense Playbook

This article walks through a real‑world pod compromise, breaks down the six‑layer Kubernetes attack surface, and presents a step‑by‑step, enterprise‑grade defense framework—including supply‑chain hardening, identity isolation, network segmentation, secret management, runtime detection, and automated response—to build a verifiable, scalable, and continuously enforceable security posture.

Cloud Architecture
Cloud Architecture
Cloud Architecture
From a Compromised Pod to Enterprise‑Grade Kubernetes Security: A Deep‑Defense Playbook

1. Real‑world attack chain

At 3 am a monitoring alert shows a production order‑service pod establishing a persistent TLS connection to an unknown public IP, the node becomes NotReady, and the security team discovers that the attacker has read several Secrets and is enumerating other workloads. The chain consists of:

Exploiting an unpatched Java dependency inside the container.

Running as root with extra toolchains that enable payload download and persistence.

Auto‑mounted high‑privilege ServiceAccount token used to call the API server.

Overly permissive RBAC allowing read of ConfigMaps, Secrets, and pod information.

Cluster‑wide default network connectivity enabling lateral scans of Redis, MySQL, Kafka, and internal admin interfaces.

Static Secrets stored in etcd without rotation, amplifying data loss.

The key insight is that the security boundary is not the pod or node but a dynamic boundary formed by many weak constraints; any single failure can let the attack spread.

2. Correct security model – six layers

Supply‑chain layer : source code, dependencies, images, artifacts – protect with SBOM, vulnerability scanning, image signing, and admission verification.

Cluster control layer : API server, etcd, scheduler, controller – protect with API audit, RBAC, etcd encryption, and control‑plane isolation.

Workload layer : pod, container, ServiceAccount – protect with PSA, securityContext, and least‑privilege ServiceAccounts.

Network communication layer : east‑west, north‑south, DNS, service mesh – protect with NetworkPolicy, mTLS, and L7 authorization.

Data & key layer : Secrets, config, DB credentials – protect with external secret managers, dynamic credentials, and rotation.

Runtime & response layer : processes, syscalls, anomalous connections – protect with eBPF monitoring, anomaly detection, and automatic isolation.

These can be abstracted into a three‑line “defense in depth” model:

First line – Prevention : block insecure images, disallow non‑compliant pods, enforce least‑privilege identities.

Second line – Limitation : assume something will slip through and restrict what it can do (default‑deny network, read‑only root filesystem, minimal permissions).

Third line – Detection & Response : quickly detect anomalies (Falco, eBPF) and cut off the workload (automatic isolation, credential revocation).

3. Detailed defensive layers

3.1 Workload hardening – Pod Security Admission (PSA)

Since Kubernetes 1.25 the legacy PodSecurityPolicy is removed. PSA defines three levels: privileged, baseline, and restricted. The recommended rollout is:

Core system namespaces – whitelist specific pods.

Regular business namespaces – enforce restricted.

Legacy workloads – start with audit + warn, then switch to enforce.

Example namespace configuration:

apiVersion: v1
kind: Namespace
metadata:
  name: prod-order
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted

3.2 Production‑grade SecurityContext

A realistic deployment template that enforces non‑root execution, read‑only root filesystem, seccomp profile, and disables token auto‑mount:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: prod-order
spec:
  replicas: 6
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      serviceAccountName: order-service-sa
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        fsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: app
        image: registry.example.com/order-service:2.3.7
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: JAVA_TOOL_OPTIONS
          value: "-XX:MaxRAMPercentage=75 -Djava.security.egd=file:/dev/urandom"
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: logs
          mountPath: /app/logs
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
        resources:
          requests:
            cpu: "500m"
            memory: "1024Mi"
          limits:
            cpu: "2"
            memory: "2048Mi"
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
      volumes:
      - name: tmp
        emptyDir: {}
      - name: logs
        emptyDir: {}

Key take‑aways: readOnlyRootFilesystem: true may break some Java apps; mount a writable /tmp if needed.

Log frameworks should write to stdout or a dedicated writable volume.

Enforcing seccompProfile: RuntimeDefault limits system calls.

Disabling token auto‑mount prevents silent credential exposure.

3.3 Image hardening & supply‑chain security

Recommendations:

Base images should be distroless or alpine with no shells, package managers, or debugging tools.

Fix UID/GID, avoid creating users at runtime.

Use multi‑stage builds to shrink layers.

Explicitly set ENTRYPOINT to avoid long execution chains.

Example Dockerfile for a Java service:

FROM maven:3.9.9-eclipse-temurin-21 AS builder
WORKDIR /workspace
COPY pom.xml .
COPY src ./src
RUN mvn -B -DskipTests clean package

FROM gcr.io/distroless/java21-debian12:nonroot
WORKDIR /app
COPY --from=builder /workspace/target/order-service.jar /app/order-service.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/order-service.jar"]

3.4 Identity isolation – ServiceAccount & RBAC

Principles:

Each workload gets its own ServiceAccount.

Do not mount the token unless the pod needs to call the API.

Scope permissions to specific resources, namespaces, verbs, and optionally resource names.

Example ServiceAccount and Role:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: order-service-sa
  namespace: prod-order
automountServiceAccountToken: false
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: order-service-role
  namespace: prod-order
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["order-service-config"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: order-service-rb
  namespace: prod-order
subjects:
- kind: ServiceAccount
  name: order-service-sa
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: order-service-role

For API access, use short‑lived projected ServiceAccount tokens:

apiVersion: v1
kind: Pod
metadata:
  name: policy-agent
  namespace: platform-security
spec:
  serviceAccountName: policy-agent-sa
  automountServiceAccountToken: false
  containers:
  - name: agent
    image: registry.example.com/policy-agent:1.0.0
    volumeMounts:
    - name: kube-api-token
      mountPath: /var/run/secrets/tokens
      readOnly: true
  volumes:
  - name: kube-api-token
    projected:
      sources:
      - serviceAccountToken:
          path: token
          expirationSeconds: 3600
          audience: kubernetes.default.svc

3.5 Network segmentation – default‑deny NetworkPolicy

Start with a namespace‑wide default deny policy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: prod-order
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Then add business‑specific allow rules. Example for an e‑commerce order service:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: order-service-policy
  namespace: prod-order
spec:
  podSelector:
    matchLabels:
      app: order-service
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: prod-gateway
      podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: prod-order
      podSelector:
        matchLabels:
          app: order-db
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: prod-inventory
      podSelector:
        matchLabels:
          app: inventory-service
    ports:
    - protocol: TCP
      port: 8080
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: middleware
      podSelector:
        matchLabels:
          app: kafka
    ports:
    - protocol: TCP
      port: 9092
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

For large clusters, generate policies automatically from a service‑dependency graph, store them in GitOps, and validate with tools like Cilium/Hubble.

3.6 Secret management – external secret stores

Kubernetes Secrets are only a delivery mechanism. For production, move credentials to external secret managers (Vault, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault) and use short‑lived, workload‑bound tokens.

Typical Vault workflow:

Pod runs with its own ServiceAccount.

Vault Kubernetes auth validates the ServiceAccount.

Vault issues a dynamic PostgreSQL credential with a TTL (e.g., 30 min).

Application reads the credential via a sidecar injector.

Vault injector example:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  namespace: prod-order
spec:
  template:
    metadata:
      annotations:
        vault.hashicorp.com/agent-inject: "true"
        vault.hashicorp.com/role: "order-service-role"
        vault.hashicorp.com/agent-inject-secret-db-creds: "database/creds/order-service"
        vault.hashicorp.com/agent-inject-template-db-creds: |
          {{- with secret "database/creds/order-service" -}}
          spring.datasource.username={{ .Data.username }}
          spring.datasource.password={{ .Data.password }}
          {{- end }}
    spec:
      serviceAccountName: order-service-sa
      containers:
      - name: app
        image: registry.example.com/order-service:2.3.7
        env:
        - name: SPRING_CONFIG_IMPORT
          value: "optional:file:/vault/secrets/db-creds"

Advantages: credentials are short‑lived, bound to the workload identity, and fully auditable.

3.7 Control‑plane hardening

Enable audit logging and forward logs to a central system.

Disable anonymous access.

Restrict the system:masters group.

Enable API Priority and Fairness (APF) to protect the control plane from request storms.

Encrypt secrets at rest with a static key and rewrite existing objects.

Enforce mTLS between API server and etcd.

Keep etcd off the public internet and isolate it on a dedicated network.

Sample etcd encryption configuration (only the relevant snippet):

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  - configmaps
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: BASE64_ENCODED_32_BYTE_KEY
  - identity: {}

3.8 Runtime detection & automated response

Falco remains valuable because many malicious actions happen at the syscall level. Example rule detecting an interactive shell spawned from a Java process:

- rule: Unexpected shell in java container
  desc: Detect an interactive shell spawned from a Java process inside a container
  condition: >
    spawned_process and container and
    proc.name in (bash, sh, zsh) and
    proc.pname in (java, java11, java17, java21)
  output: Shell spawned from Java process (user=%user.name container=%container.name pod=%k8s.pod.name namespace=%k8s.ns.name shell=%proc.name parent=%proc.pname cmd=%proc.cmdline)
  priority: CRITICAL

Automated response chain:

Falco emits an alert.

Alert is sent to SIEM / Alertmanager.

Automation tags the offending pod with security-state=quarantine.

A NetworkPolicy that selects the quarantine label drops all ingress and egress.

Optionally revoke Vault credentials or cloud IAM tokens.

Notify on‑call engineers and create a ticket.

Quarantine NetworkPolicy:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: quarantine
  namespace: prod-order
spec:
  podSelector:
    matchLabels:
      security-state: quarantine
  policyTypes:
  - Ingress
  - Egress

4. End‑to‑end case study – securing the prod-order namespace

The article walks through a four‑week transformation:

Week 1 – Identity & baseline : create dedicated ServiceAccounts, disable token auto‑mount, switch namespace to PSA restricted, remove privileged, hostPath, and root containers.

Week 2 – Network isolation : apply default‑deny NetworkPolicy, generate allow rules based on observed traffic, restrict egress to DNS, Kafka, DB, and required third‑party APIs.

Week 3 – Secrets & supply‑chain : migrate DB credentials to Vault dynamic accounts, add SBOM generation, vulnerability scanning, and image signing in CI; enforce admission checks for signatures and disallow latest tags.

Week 4 – Detection & response : deploy Falco with critical rules, collect API audit logs, implement automatic quarantine workflow.

Post‑remediation benefits include limited lateral movement, short‑lived credential windows, blocked untrusted images, and minute‑level isolation of anomalous pods.

5. Roadmap for large‑scale environments

Baseline : PSA baselinerestricted, disable default ServiceAccount tokens, universal image scanning, default‑deny NetworkPolicy, enable API audit.

Critical gaps : enforce non‑root containers, least‑privilege RBAC, external secret managers, image signing, mTLS for critical services.

Close the loop : integrate runtime detection with a central event bus, automate isolation and credential revocation, automate RBAC pruning, generate network dependency graphs for policy back‑fill.

Zero‑trust : unified workload identity (SPIFFE/SPIRE), full L7 authorization, multi‑cluster policy governance, regular security chaos engineering.

Key governance practices: policy‑as‑code with GitOps, staged rollout (audit → enforce), environment‑specific parameterization, periodic baseline scans, and continuous security drills.

6. Pre‑deployment checklist

All pods define a securityContext and avoid privileged, hostNetwork, and unnecessary hostPath.

Run containers as non‑root and disable automatic ServiceAccount token mounting.

Each service has a dedicated ServiceAccount with minimal RBAC; no wildcard * verbs on high‑privilege resources.

Production namespaces enforce default‑deny NetworkPolicy and only allow required dependencies (DNS, monitoring, logging, DB, Kafka, etc.).

High‑value secrets are stored in external secret managers with dynamic credentials and rotation.

etcd encryption is enabled and existing data has been rewritten.

CI pipelines generate SBOMs, run vulnerability scans, sign images, and reject latest tags.

API audit logging is active; runtime anomaly detection (Falco/eBPF) is deployed.

Automated isolation and credential revocation mechanisms are in place; regular security drills are scheduled.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KubernetessecurityRBACNetworkPolicySupplyChainPodSecurityAdmissionRuntimeDetection
Cloud Architecture
Written by

Cloud Architecture

Focuses on cloud‑native and distributed architecture engineering, sharing practical solutions and lessons learned. Covers microservice governance, Kubernetes, observability, and stability engineering to help your systems run stable, fast, and cost‑effectively.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.