📦 Kubernetes

What is it?

  • Concept: Kubernetes (K8s) is a container orchestration platform — it takes a fleet of machines (Nodes) and schedules, networks, and heals containers (grouped into Pods) across them according to a declarative desired state stored centrally. Almost every attack surface below comes from the fact that a cluster is really a distributed system of independent network services (API server, kubelet, etcd, kube-proxy) that all trust each other by design, and the interesting question for an attacker is always “which one of these services is reachable, and does it actually check who’s asking?”
  • Impact: The blast radius of a Kubernetes misconfiguration is rarely “one container” — a single over-exposed or under-authenticated component (kubelet, the API server, an over-permissioned ServiceAccount) tends to be the thing standing between “I have a shell in one Pod” and “I can read every Secret in the cluster or mount the host filesystem of every Node.”

How it works

  1. Control plane (usually one or more dedicated Nodes): the API server (8443, HTTPS) is the single front door everything else talks through — kubectl, the scheduler, the controller manager, and every kubelet all read/write cluster state exclusively via its REST API, backed by etcd (2379 client / 2380 peer), the cluster’s key-value datastore.
  2. Worker Nodes: each runs a kubelet (10250 HTTPS by default) — the agent that actually starts/stops containers on that Node per instructions from the API server — and kube-proxy (10256 healthz, 10249 metrics), which programs the Node’s networking rules for Service routing.
  3. Pods are the actual unit of scheduling — one or more containers sharing a network namespace. Kubernetes injects a ServiceAccount identity into every Pod by default, mounted at /var/run/secrets/kubernetes.io/serviceaccount/ (token, ca.crt, namespace), so that workloads can call back into the API server as themselves.
  4. RBAC (Role-Based Access Control) governs what any given identity — a ServiceAccount, a user, a group — is actually authorized to do against the API server: which verbs (get/list/create/delete/…) on which resources (pods/secrets/nodes/…), scoped to a namespace (Role/RoleBinding) or cluster-wide (ClusterRole/ClusterRoleBinding).

Component / Port Reference

ComponentDefault PortRole
API server6443/8443 (HTTPS)Single source of truth — every other component and every kubectl call goes through here
etcd2379 (client), 2380 (peer)Backing key-value store for all cluster state — direct access is equivalent to full cluster compromise
kubelet10250 (HTTPS, authenticated by default), historically 10255 (HTTP, read-only, unauthenticated)Per-Node agent — executes Pod lifecycle actions and exposes an API for exec/run/logs/stats against its own Node
kube-proxy10256 (healthz), 10249 (metrics)Programs Service routing (iptables/IPVS) on the Node; these two ports are diagnostic, not part of the attack surface directly

Security Quirks & Niche Facts

  • The kubelet has its own independent API and its own independent auth story — a cluster can lock the API server down perfectly and still lose everything through kubelet misconfiguration, because nothing forces the two to agree on an authentication policy. See Kubernetes - Kubelet API Anonymous Access.
  • A ServiceAccount token is scoped by RBAC, not by “being inside a Pod” — a token pulled out of a low-value Pod (e.g. a public-facing nginx container that has nothing to do with Kubernetes itself) is just as usable from outside the cluster, against the API server directly, as it is from inside. Compromising the least interesting Pod in the cluster is often enough if its ServiceAccount happens to be over-permissioned.
  • kubectl auth can-i --list is the fastest way to find the actual boundary of a stolen identity — RBAC is deny-by-default and additive, so this one command answers “what can I actually do with this token” without needing to read every Role/ClusterRole object by hand.
  • create on pods is frequently underestimated as a permission — a ServiceAccount that can merely create Pods (nothing about Secrets, nothing about RBAC itself) can still escalate to full Node compromise by defining the Pod’s own spec, see Kubernetes - Malicious Pod Creation (hostPath Escape).
  • Namespaces are an organizational boundary, not a security boundary by default — kube-system Pods (etcd, CoreDNS, the API server’s own static Pods) sit in the same cluster network as default-namespace application Pods unless NetworkPolicies say otherwise, so a foothold in an unrelated app Pod often has direct line-of-sight to control-plane components.

Exploitation

Mitigation

  • Fix 1: Disable kubelet anonymous authentication (--anonymous-auth=false) and require webhook authorization (--authorization-mode=Webhook) — anonymous, unauthenticated access to /pods, /exec, /run should never be reachable from outside the cluster’s trusted network.
  • Fix 2: Apply least-privilege RBAC to every ServiceAccount, and explicitly disable auto-mounting (automountServiceAccountToken: false) on any Pod that never calls the API server — most application workloads (an nginx frontend, a database) have no legitimate reason to hold a live cluster credential at all.
  • Fix 3: Restrict who can create Pods with a Pod Security Admission policy (baseline/restricted) or an admission controller (OPA/Gatekeeper, Kyverno) that rejects hostPath volumes, hostNetwork, and hostPID outside of explicitly trusted namespaces — create on pods should not implicitly mean “root on every Node.”
FileCreated
HTB Machine - SteamCloudJuly 27, 2026

References: