← All guides

Infrastructure & CIS benchmarks

Posture & operations
On this page

In plain terms

IaC scanning checks what your infrastructure is supposed to look like (the files). Infrastructure posture scanning checks what is running right now, meaning the live cloud account, the running Kubernetes cluster and the host, against established hardening baselines. The best-known baselines are the CIS Benchmarks, from the Center for Internet Security: consensus-driven, prescriptive hardening guides for almost every platform (AWS, Kubernetes, Linux, Docker, and more).

Why it matters

Reality drifts from declaration. Someone toggles a setting in the console during an incident, a default is less strict than you assumed, a cluster was set up before your standards existed. IaC scanning never sees any of that, and only a check against the running system does. CIS Benchmarks give you an objective, widely-recognized bar to measure against (and often to prove compliance against).

On a managed cluster, half the benchmark is not yours A CIS benchmark checks the whole cluster, including parts a managed platform runs and nobody using it can change. Declaring the cluster as provider-operated keeps those findings reported and counted but out of the list of work. The kubelet stays yours because node pool settings reach it, and RBAC, Pod Security and network policy are yours whoever runs the cluster underneath. THE PROVIDER RUNS IT kube-apiserveretcd kube-controller-managerkube-proxy Reported and counted. Never listed as work you can do. STILL YOURS kubeletRBAC Pod Securitynetwork policy Yours whoever runs the cluster, and usually what matters. A TOOL CANNOT WORK OUT WHICH SIDE IT IS LOOKING AT Whether a platform is managed is a fact about a contract, not something visible in a cluster, so somebody has to say. In Draugr that is one line on the infrastructure it declares.
The narrowing is deliberate. Telling somebody to reconfigure an API server they cannot reach, at the top of a list, teaches them the list is not worth reading.

Draugr's kubernetes control does this against a cluster your descriptor names, with draugr-k8s-policies reading the cluster directly by default and kube-bench available as an opt-in second opinion. The control catalog lists what each one covers.

A cluster is declared once in the descriptor, under clusters:, and each component names the clusters it runs on. Which findings are yours is the cluster's operatedBy field, self by default or provider for a managed platform, described in the Saga schema.

The cloud control checks a live Google Cloud project against the CIS Google Cloud Platform Foundation Benchmark, through Prowler, which you install. The account is declared once, under accounts:, and each component names it from its cloud: entry, optionally narrowed to regions. Findings about the account as a whole, its IAM policy and audit logging, go to the component that declares the whole account. A service the scan's credentials cannot read is listed under Caveats with the permission that was denied, and its checks are not counted as passed. With failOnCaveats: [unread-checks] in the descriptor's gate, a denied read fails the run until the grant is fixed. The Saga schema has the fields.

Where it fits

  • Artifact: live infrastructure, whether a cloud account, a cluster or a host.
  • Stage: continuously and on a schedule against running environments (not a PR-time check, there's no file to look at, there's a system to inspect).

How it works

A posture scanner authenticates to the environment and evaluates its actual configuration against a benchmark's checks, for example "the API server doesn't allow anonymous auth," "no security group allows 0.0.0.0/0 to port 22," "audit logging is enabled." It reports pass/fail per control with remediation guidance, often producing a compliance-style score.

ToolNotes
kube-benchOSS; CIS Kubernetes Benchmark against a live cluster
ProwlerOSS; AWS/Azure/GCP posture + compliance checks
ScoutSuiteOSS; multi-cloud posture auditing
OpenSCAPOSS; host-level compliance (CIS/STIG)
CIS BenchmarksThe baselines themselves

Common pitfalls

  • Benchmarks need tailoring. Not every CIS control fits every environment; expect to justify and document exceptions rather than chase 100%.
  • Posture ≠ IaC. You need both, with IaC to prevent misconfigs going in and posture to catch drift and pre-existing state.
  • Credentials and blast radius. Posture scanners need read access to your environment; scope those credentials carefully.
How Draugr fits. The kubernetes and cloud controls ship today. A cluster or a cloud account belongs to a component the way a repository does, so it sits in the same descriptor, its findings take the same P1–P4 ranking from the component's declared exposure and criticality, and they land in the same report as your dependency and code findings.

Two checks reach two different halves of the benchmark, because the halves live in different places:

What it readsWhat it needs
The native check, on by defaultthe benchmark's policies section through the Kubernetes API: RBAC, service accounts, Pod Security Standards, network policies, secrets usagenothing. It means the same from a laptop or from CI, and creates nothing in your cluster
kubeBenchJob, opt-inAPI server manifests, kubelet configuration and etcd file permissions, which are files on a nodea short-lived Job on that node, read and then deleted. It mutates the cluster and wants a privileged pod, so Draugr will not run it until you accept both effects in the descriptor

Reading the API directly is what keeps the first one quick on a large cluster. The same section answered through kube-bench shells out to kubectl once per check, and once per pod for the pod-security ones.

Read a clean policies result carefully. That section is the benchmark's advisory one, and CIS marks every check in it manual, so it tells you what to review rather than what it measured. The scored checks are the ones about how the nodes and control plane were configured, which is the half behind the Job.

On a managed cluster the control plane is not yours to inspect by any means, so scanning the nodes is the useful setting there. Either way the report states which checks ran.

A cluster is often shared, and a component may own only part of it. The API-backed check takes a namespaces list and narrows to it, and the report names the scope it measured. The checks about the cluster as a whole, such as ClusterRoleBindings and admission webhooks, run only for a component that declares the whole cluster, so a shared cluster's answer is filed once. A node's filesystem has no namespace, so the Job-based checks always describe the whole cluster, and Draugr does not run them against a component that claimed part of one: a report that looked scoped while listing somebody else's namespaces would be worse than a missing one. It says which scanner went unanswered for which component, under Caveats. Name the cluster from two components, one narrowed and one whole, and each check runs where it can answer.

Keep learning