Expert · DevSecOps · topic 49 of 53 · 35 min
Kubernetes security
Explanation
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).
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.iokubectl 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?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.
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: 8080Pod 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.)
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: restrictedThe 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".
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: {}| Setting | What it prevents |
|---|---|
| runAsNonRoot: true | Starting the container as root (user 0) |
| allowPrivilegeEscalation: false | A process gaining more privileges than its parent, for example through setuid programs |
| readOnlyRootFilesystem: true | Writing 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.
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
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)
Which command checks whether the ServiceAccount ci-deployer in namespace canteen may delete pods?
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").
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
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Secrets managementDevSecOps · same module
- DevSecOps: shifting security leftDevSecOps · same module
- Why Kubernetes, and how a cluster worksKubernetes fundamentals
- Pods, ReplicaSets and DeploymentsKubernetes fundamentals
- Services, Ingress and the Gateway APIKubernetes fundamentals
- Managed Kubernetes: EKS, AKS and GKECloud Computing (AWS, Azure, Google Cloud) · Containers in the cloud
Questions people ask about this
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.
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.
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.
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.
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
- This is the last topic of “DevSecOps”. The module exam comes next.
- Module 11 exam: DevSecOps · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
- Then the next module, GitOps, platform engineering and DevOps careers. 53 topics left in the course before the final exam.