← mohdarif.com
Kubernetes Security Series · Part 1 of 3

How Kubernetes Works

Architecture, how a request flows, and the core objects, with diagrams.

You cannot secure Kubernetes well without knowing how it works. This part covers the basics that Parts 2 and 3 build on, and notes why each piece matters for security.

1. The problem Kubernetes solves

A container packages an app with everything it needs to run. Running one is easy. Running hundreds across many machines is not:

Kubernetes (K8s) is a container orchestrator that handles all of this. You describe what you want ("run 3 copies of this image and expose port 80"), and Kubernetes keeps working to make the cluster match. It constantly compares the desired state with the actual state and fixes any difference. Most of what follows is built on that idea.

2. Cluster architecture

A cluster has a control plane, which makes decisions, and worker nodes, which run your apps.

kubectl / CI pipeline HTTPS :6443 CONTROL PLANE etcd key-value store all cluster state kube-apiserver front door for everything only component that talks to etcd scheduler picks a node for each new Pod controllers drive actual state toward desired kubelets watch and report to the API server WORKER NODE 1 kubelet kube-proxy runtime Pod app sidecar Pod app WORKER NODE 2 kubelet kube-proxy runtime Pod app Pod app
Figure 1. Cluster architecture. Solid arrows are connections between components. Dashed arrows show the scheduler and controllers watching the API server for changes.

Control plane

Worker node

Why it matters for security

ComponentPortWhat an attacker gains
kube-apiserver6443Whoever authenticates here with enough RBAC rights controls the cluster. Anonymous access or an over-privileged token is the usual way in.
etcd2379 / 2380Direct read access exposes every Secret. Write access allows tampering with any object. It should accept only API server connections, with mutual TLS.
kubelet10250If its API allows anonymous or weakly authorized requests, an attacker can exec into any Pod on that node and read its logs.
Container runtimelocal socketAccess to the runtime socket (or a privileged Pod) is effectively root on the node.

3. What happens when you run kubectl apply

Every change goes through the same steps. Knowing them shows where you can add security controls.

INSIDE THE API SERVER kubectl apply sends YAML over HTTPS 1 Authentication who are you? cert, token, OIDC 2 Authorization are you allowed? RBAC 3 Admission mutate, validate, policy checks 4 etcd object is stored (desired state) fail: 401 fail: 403 fail: rejected THEN CONTROLLERS ACT ON THE STORED OBJECT Controllers Deployment → ReplicaSet → Pods Pods created, not yet placed Scheduler chooses a node for each Pod writes the binding to the API kubelet + runtime pulls the image, starts containers reports status back
Figure 2. A request must pass authentication, authorization and admission before it is stored. Components then react to the new object, each through the API server.
  1. Authentication: the API server identifies the caller from a client certificate, bearer token (including ServiceAccount tokens), or an OIDC identity.
  2. Authorization: RBAC decides whether that identity may perform this verb (create, get, delete) on this resource in this namespace.
  3. Admission: mutating admission controllers can modify the object (inject a sidecar, set defaults). The request is then validated against the schema, and validating admission controllers can reject it. This is where Pod Security Admission and policy engines such as Kyverno or OPA Gatekeeper enforce rules like "no privileged containers".
  4. Persist: the object is written to etcd as desired state.
  5. Reconcile: controllers, the scheduler and kubelets notice the change and act on it, always by reading and writing through the API server.

RBAC controls who can create objects. Admission controls what those objects can contain. Someone allowed to create Pods can still be blocked from creating a privileged Pod, but only if an admission policy is in place.

4. The objects you will keep seeing

TRAFFIC PATH MANAGEMENT PATH Ingress host and path rules Service stable IP, selects by label Deployment rolling updates ReplicaSet keeps N Pods running Podapp=web Podapp=web Podapp=web
Figure 3. Traffic reaches Pods through an Ingress and a Service. Pods are created and replaced by a ReplicaSet, which a Deployment manages. The Service finds Pods by label, not by name or IP.
ObjectWhat it isSecurity angle
PodSmallest deployable unit. One or more containers sharing network and storage.Where code runs. Its securityContext decides privileges.
DeploymentDeclares how many Pods and which image. Handles rollouts and rollbacks.The image reference here is the start of the supply chain (Part 2).
ServiceStable virtual IP and DNS name in front of changing Pods.Type LoadBalancer or NodePort exposes it outside the cluster.
IngressHTTP routing rules from outside to Services.Public entry point. TLS and WAF decisions live here.
NamespaceA logical partition of the cluster.Scope for RBAC and policies. It is not a security boundary by itself.
ConfigMap / SecretConfiguration data / sensitive data.Secrets are only base64-encoded in etcd unless encryption at rest is enabled.
ServiceAccountIdentity a Pod uses to talk to the API server.A token is mounted into Pods by default. A compromised Pod gets its permissions.
Role / RoleBindingRBAC permissions, and who they are granted to.Wildcards and cluster-admin bindings are common findings.
NetworkPolicyAllowed traffic between Pods.Without one, all Pods can reach all other Pods.

A minimal example

Two objects: a Deployment that runs three copies of an app, and a Service that exposes them inside the cluster.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
      - name: web
        image: registry.example.com/web:1.4.2
        ports: [{ containerPort: 8080 }]
---
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  selector: { app: web }
  ports: [{ port: 80, targetPort: 8080 }]

Delete one of the three Pods and the ReplicaSet creates a replacement within seconds. That self-healing is the control loop from section 1 at work. This manifest also has security gaps: no securityContext, no resource limits, and an image tag instead of a digest. The next parts cover how to fix them.

5. Risky defaults

A few defaults explain many real cluster compromises:

These often combine into one attack. The attacker exploits a vulnerable app in a Pod, reads the mounted ServiceAccount token, uses an over-privileged role to create a privileged Pod, escapes to the node, and then reaches other workloads and Secrets. A control at any of these steps can stop it.

6. Next

The image in that Deployment is code that came from somewhere. Part 2 covers how to build, sign, scan and verify images, and how to enforce those checks in the cluster.

Part 2: Supply chain security →

References