Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cluster hardening

The Kubernetes chapter documents the chart. This section is the other half: an audit of this deployment against the OWASP Kubernetes Security Cheat Sheet, split by who can actually apply each control.

That split is the point. A workload chart controls its pod security context, its resource bounds, its NetworkPolicy, its ServiceAccount and how it consumes secrets. It cannot patch a node, set an API-server flag, configure etcd, authenticate a kubelet, or install an admission controller. For those, the honest deliverable is not a setting but a statement of what you owe and what happens if you do not, because a deployment that inherits an unchecked assumption is not secured by the chart’s own hardening.

Important

Several controls here are ones no application-level hardening can compensate for. If the kubelet accepts anonymous requests, or anything untrusted can read etcd, then every control this project ships (non-root, read-only rootfs, dropped capabilities, RBAC, ABAC, the audit trail) is bypassable, because the attacker is beneath the layer they operate in. Those are marked where they appear.

Claims about what the chart renders are checked against the chart’s own render gates. Claims about what a cluster then applies come from the deployment probe harness, which reads each answer from the layer that actually decides it (the container runtime’s own spec for the security context, the API server for admission, the EndpointSlice for readiness) and which declares in its own record what it did not exercise, so silence is never read as coverage.

The five pages

PageCovers
The cluster: hosts, control plane, accessnode and OS hardening, the supported version window, rolling upgrades, advisories, etcd, the port surface, cluster API access, cluster RBAC, kubelet authentication
Images: build, provenance, scanningthe distroless image and what it costs you during an incident, keyless signing and the identity to trust, copyable admission policies, scanning after release, the full supply-chain map
The workload: security context & admissionthe applied security context, user namespaces, AppArmor, Restricted-profile compliance versus enforcement, sandboxing, kernel modules
Namespaces, network & policynamespace scoping, one instance per organisation, the service-mesh decision, which admission engine, resource bounds in four layers, deny-by-default egress
Secrets, detection & responseSecrets at rest and exactly what ours contain, runtime detection on a shell-less image, per-replica alerting, breach containment and credential rotation, the two log streams, managed control planes

The ownership map

Cheat-sheet controlOwnerWhere
Host hardening, OS patching, node firewalloperatorcluster
Supported Kubernetes version windowoperator (chart states the floor)cluster
Rolling upgrades rather than mutating containerschartcluster
Kubernetes security advisoriesoperatorcluster
Kubernetes Dashboardoperator (we ship none)cluster
etcd access + encryption at restoperatorcluster
Control-plane and kubelet portsoperatorcluster
The workload’s own port surfacechartcluster
Cluster API access control, MFAoperatorcluster
Cluster RBAC (Node,RBAC, NodeRestriction)operatorcluster
The workload’s own RBACchart, deliberately nonecluster
Kubelet authentication/authorizationoperatorcluster
Minimal, current, authorized imageschart/CIimages
Image provenance at admissionoperator (we publish the attestations)images
Continuous scanning of published imagesCIimages
Supply chainCI, with two gapsimages
Pod/container security contextchartworkload
Pod Security Admission enforcementoperator (one kubectl label)workload
Container sandboxingneither; a recorded decisionworkload
Kernel-module loadingsatisfied by the chartworkload
Namespace isolationchart (namespace-scoped by construction)network
Service meshneither; a recorded decisionnetwork
Centralized policy managementoperator, for admission onlynetwork
Container resource boundschartnetwork
Namespace ResourceQuota/LimitRangeoperatornetwork
Egress restrictionchart (mechanism) + operator (destinations)network
Secrets encrypted at restoperatorsecrets
Runtime/syscall detectionoperator (unusually cheap here)secrets
Replica behavioural deviationoperator (from metrics we publish)secrets
Breach containment + credential rotationoperator (procedure is ours)secrets
Cluster API audit loggingoperatorsecrets
Container loggingchart/appsecrets
Managed control planeprovidersecrets

Final thoughts: the three practices, checked

The cheat sheet closes with three practices rather than controls. Checking them against what this project actually ships, rather than claiming them:

“Embed security into the container lifecycle as early as possible”: evidenced. Security here is CI, not a review checklist: the chart’s render gate parses every rendered object and asserts the Restricted profile per container, the golden renders pin the exact bytes, the secret-leak gate refuses a credential that would reach a ConfigMap, the image scanners run at build and again on a schedule against the published tags, cargo deny runs on every change, and zizmor and CodeQL read the workflows themselves. Each of those refuses a merge rather than filing a comment, and each of the chart-side ones has been watched to fail deliberately; a gate nobody has seen fail is a gate nobody knows works.

“Use Kubernetes-native controls to reduce operational risk”: evidenced. The chart’s controls are the platform’s own: a NetworkPolicy rather than an in-app firewall, a security context and the Restricted profile rather than a hardening sidecar, resource limits rather than in-process throttling alone, probes rather than an external watchdog, a user namespace rather than a trusted UID, and no service mesh because what one would add is either already provided or not needed at this shape. The one place we did not take a native control is Pod Security Admission, and that is because labelling a namespace is not a chart’s call, stated as the operator’s rather than quietly skipped.

“Leverage the context Kubernetes provides to prioritize remediation”: partly, and here is the honest version. The generic form of this practice is to rank findings by whether the affected code is reachable in your deployment. This project’s answer is the OpenVEX documents: when a scanner reports advisories in a privilege-dropping helper that opens no socket and parses no untrusted input, the response is a machine-readable not_affected statement with a controlled-vocabulary justification and an impact_statement a reader can check, not a silenced ignore list, and not a rebuild that fixes nothing.

That mechanism has a cost, and stating it is what makes the claim honest: a VEX statement is a claim about today’s binary, and it must be re-checked on every base-image bump. When upstream rebuilds that helper, statements about it become obsolete, and a stale not_affected is worse than no VEX at all: it is an argument that has quietly stopped being true while still suppressing its finding. The scheduled scan is what surfaces a finding whose statement no longer matches, and the re-check itself is a human obligation, not an automated one.