Skip to content

Expert · DevSecOps · topic 49 of 53 · 35 min

Kubernetes security

Explanation

Securing Kubernetes means limiting who can do what (RBAC and ServiceAccounts), which pods can talk to which (NetworkPolicies), and what a container may do on its node (Pod Security Standards and securityContext). Add admission policies for images, protect Secrets, keep the cluster patched and watch the audit logs.

Every request goes through three checks

Everything in Kubernetes happens through the API server, whether it is kubectl, a CI job or a controller. Each request passes three steps: authentication (who are you?), authorisation (are you allowed to do this?) and admission control (does this object follow our rules, and should it be changed?). Security in a cluster is mostly about getting those three right, plus limiting what running containers can do.

RBAC: who can do what

RBAC (role-based access control) has four objects. A Role lists allowed actions (verbs like get, list, create) on resources inside one namespace. A ClusterRole does the same for the whole cluster, or as a reusable template. A RoleBinding gives a Role, or a ClusterRole, to someone inside one namespace. A ClusterRoleBinding gives a ClusterRole across the whole cluster. The "someone" is a user, a group or a ServiceAccount: an identity for pods and programs rather than people. RBAC only adds permissions; there are no deny rules, so start from nothing and add only what is needed (least privilege).

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: canteen-api
  namespace: canteen
automountServiceAccountToken: false   # the app does not call the Kubernetes API
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: read-config
  namespace: canteen
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployer-read-config
  namespace: canteen
subjects:
  - kind: ServiceAccount
    name: ci-deployer
    namespace: canteen
roleRef:
  kind: Role
  name: read-config
  apiGroup: rbac.authorization.k8s.io
A ServiceAccount, a Role that can only read ConfigMaps in one namespace, and a binding that grants it.
bash
kubectl auth can-i list secrets -n canteen --as=system:serviceaccount:canteen:ci-deployer
kubectl auth can-i --list -n canteen --as=system:serviceaccount:canteen:ci-deployer
kubectl get clusterrolebindings -o wide | grep cluster-admin     # who has full control?
kubectl auth can-i answers "yes" or "no" for one action, or lists everything an identity may do.
Careful: Being allowed to get or list Secrets means being able to read every Secret in that namespace. Treat that permission like a master key, and avoid wildcards such as resources: ["*"] and verbs: ["*"].

NetworkPolicies: who can talk to whom

By default every pod can reach every other pod in the cluster. If one pod is compromised, it can talk to your database directly. A NetworkPolicy selects pods by label and lists the traffic allowed in (ingress) or out (egress). The usual pattern is a default deny policy for the namespace, then small "allow" policies for the flows you need. NetworkPolicies only work if your network plugin (CNI) enforces them, for example Calico or Cilium; with a plugin that does not, they are silently ignored.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: canteen
spec:
  podSelector: {}          # every pod in the namespace
  policyTypes: ["Ingress"]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-to-api
  namespace: canteen
spec:
  podSelector:
    matchLabels:
      app: canteen-api
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: canteen-web
      ports:
        - protocol: TCP
          port: 8080
Deny all incoming traffic, then allow only the web pods to reach the API on port 8080.
Tip: If you also deny egress (outgoing traffic), remember to allow DNS (port 53 to the cluster DNS pods), or every lookup will fail.

Pod Security Standards and securityContext

Pod Security Standards define three levels. Privileged has no restrictions (for trusted system components). Baseline blocks known dangerous settings such as privileged containers and host networking. Restricted follows current hardening practice: run as non-root, drop capabilities, no privilege escalation. The built-in Pod Security Admission controller enforces a level per namespace through labels. (The older PodSecurityPolicy was removed in Kubernetes 1.25.)

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: canteen
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/audit: restricted
enforce rejects pods that break the level; warn and audit only report.

The securityContext in a pod spec is where a container meets those rules. Each setting removes a common way for an attacker to go from "inside the container" to "in control of the node".

yaml
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: api
      image: ghcr.io/acme/canteen-api@sha256:4a1f...e9
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
      volumeMounts:
        - name: tmp
          mountPath: /tmp
  volumes:
    - name: tmp
      emptyDir: {}
A pod that passes the restricted level. The emptyDir gives the app a writable /tmp while the rest of the filesystem stays read-only.
SettingWhat it prevents
runAsNonRoot: trueStarting the container as root (user 0)
allowPrivilegeEscalation: falseA process gaining more privileges than its parent, for example through setuid programs
readOnlyRootFilesystem: trueWriting or changing files in the image, such as dropping a tool into /usr/bin
capabilities: drop ["ALL"]Using special kernel powers such as changing network settings
privileged: true (avoid)Gives the container almost full access to the node

Image policies with admission control

Admission controllers can check every new object against your rules. Policy engines such as Kyverno and OPA Gatekeeper let you write rules like "images must come from ghcr.io/acme", "the :latest tag is not allowed", "every image must have a valid cosign signature" and "every pod needs resource limits". Start new rules in audit mode, fix what they report, then enforce them.

Secrets, patching and audit logs

  • Secrets: turn on encryption at rest for Secrets in etcd (the cluster database), restrict who can read them, prefer mounting them as files over environment variables, and source them from a secret manager.
  • Patching: Kubernetes supports roughly the three most recent minor versions, each for about a year. Plan upgrades several times a year; managed services such as EKS, AKS and GKE make this easier but do not do it all for you. Patch node images too.
  • Audit logs: the API server can record who did what and when. Send these logs to your central logging or SIEM (security information and event management) system and alert on events like new ClusterRoleBindings or reading many Secrets.
  • Detection and checks: Falco detects suspicious behaviour inside running containers, and kube-bench checks a cluster against the CIS Kubernetes Benchmark.
Careful: Common mistakes: giving the CI pipeline cluster-admin "to make it work"; trusting NetworkPolicies on a CNI that does not enforce them; leaving the default ServiceAccount token mounted in every pod; running containers as root because the image was built that way; never upgrading the cluster. Check each one with kubectl auth can-i, a quick connectivity test, and the restricted Pod Security level.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Kubernetes security · 1/7

Who are you? Are you allowed? Does it follow the rules?

Every request to Kubernetes is authenticated, authorised and then checked by admission control.

Prefer a video by a teacher? Find free videos on “kubernetes security rbac network policy pod security standards tutorial” on YouTube ↗

In real life: A healthtech in Hyderabad tightens its patient-records namespace

Before an audit, a healthtech company runs kubectl auth can-i --list for each ServiceAccount and finds that an old Helm chart bound its account to cluster-admin. They replace it with a namespaced Role. They add a default-deny NetworkPolicy so only the records API can reach the database pods (their CNI, Calico, enforces it), label the namespace with the restricted Pod Security level, and fix three images that ran as root. A penetration test, done by an outside firm with written permission, later confirms that a compromised front-end pod can no longer reach the database.

Practice (0/3 done)

Task 1 · Question

Which command checks whether the ServiceAccount ci-deployer in namespace canteen may delete pods?

Task 2 · Code · Python

Write lint_pod(pod) for a pod written as a Python dict (like parsed YAML). Return a list of findings as strings. First, if spec.hostNetwork is true, add "pod: hostNetwork". Then for each container, in order, check and add "<name>: <check>" for: "privileged" (privileged is true), "runAsNonRoot" (not true in the container's securityContext, or, if the container does not set it, in the pod-level spec.securityContext), "allowPrivilegeEscalation" (not set to False), "readOnlyRootFilesystem" (not True) and "capabilities" (capabilities.drop does not contain "ALL").

Task 3 · Practice

Lock down a namespace called shop that runs three apps: web (public, behind an Ingress controller in namespace ingress-nginx), api (port 8080) and postgres (port 5432). Write the YAML (or a precise description) for the NetworkPolicies, the Pod Security label and the ServiceAccount setup.

Quick quiz

Question 1

1.What is the difference between a RoleBinding and a ClusterRoleBinding?

Question 2

2.You create a default deny NetworkPolicy, but pods can still reach each other. What is the most likely reason?

Question 3

3.Which object replaced PodSecurityPolicy (removed in Kubernetes 1.25) for enforcing Pod Security Standards?

Question 4

4.Which securityContext setting stops a process from gaining more privileges than its parent?

Question 5

5.Which tool can enforce a rule such as "images must come from our registry and must not use :latest"?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is the difference between a RoleBinding and a ClusterRoleBinding?

Answer: A RoleBinding grants permissions inside one namespace; a ClusterRoleBinding grants them across the whole cluster

RoleBindings are namespaced. ClusterRoleBindings apply cluster-wide. RBAC has no deny rules at all.

You create a default deny NetworkPolicy, but pods can still reach each other. What is the most likely reason?

Answer: The cluster's network plugin (CNI) does not enforce NetworkPolicies

NetworkPolicies are enforced by the CNI, such as Calico or Cilium. With a CNI that ignores them, nothing changes.

Which object replaced PodSecurityPolicy (removed in Kubernetes 1.25) for enforcing Pod Security Standards?

Answer: Pod Security Admission, configured with namespace labels

The built-in Pod Security Admission controller enforces privileged, baseline or restricted per namespace.

Which securityContext setting stops a process from gaining more privileges than its parent?

Answer: allowPrivilegeEscalation: false

allowPrivilegeEscalation: false blocks escalation such as through setuid binaries.

Which tool can enforce a rule such as "images must come from our registry and must not use :latest"?

Answer: Kyverno or OPA Gatekeeper

Policy engines run as admission controllers and reject objects that break your rules.

How are values in a Kubernetes Secret protected by default?Related

Answer: Only base64-encoded, which anyone with read access can decode

Base64 is an encoding. Real protection comes from RBAC, encryption at rest and external secret managers.

From Namespaces, ConfigMaps, Secrets, resources and probes

Which tools scan container images for known vulnerabilities?Related

Answer: Docker Scout and Trivy

Docker Scout and Trivy compare image packages with vulnerability databases. cosign signs images.

From Image and container security

Which component decides which node a new pod should run on?Related

Answer: kube-scheduler

The scheduler watches for pods with no node assigned and picks a node based on resources and rules.

From Why Kubernetes, and how a cluster works

What do containers in the same pod share?Related

Answer: A network identity (one IP) and optionally volumes

Containers in a pod share the network namespace, so they reach each other on localhost, and can mount the same volumes.

From Pods, ReplicaSets and Deployments

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. This is the last topic of “DevSecOps”. The module exam comes next.
  2. Module 11 exam: DevSecOps · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, GitOps, platform engineering and DevOps careers. 53 topics left in the course before the final exam.

← Previous: Software supply chain security