Schedule icon
Webhook icon
WorkingDirectory icon
Commands icon
Docker icon
Script icon
Loop icon
If icon
Create icon
SlackIncomingWebhook icon
Log icon

Audit a Kubernetes Cluster Against the CIS Benchmark with kube-bench

Run kube-bench against a cluster, count failed CIS controls, and escalate above your threshold with a GitHub issue, Slack alert, and a remediation report.

Categories
Infrastructure

Diagram unavailable

We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.

How it works

  1. weekly_cis_audit (io.kestra.plugin.core.trigger.Schedule, cron 0 6 * * 1) is the primary trigger and ships disabled: true, so nothing runs until an operator switches it on. on_demand_audit (io.kestra.plugin.core.trigger.Webhook, keyed) accepts an on-demand audit of a named cluster from a CI job or a laptop.
  2. audit_workspace (io.kestra.plugin.core.flow.WorkingDirectory) opens one shared filesystem so the scan, the parser, and the remediation report all see the same files.
  3. run_kube_bench (io.kestra.plugin.scripts.shell.Commands on the io.kestra.plugin.scripts.runner.docker.Docker runner, image aquasec/kube-bench:latest) first writes a mock-report.json fixture with a heredoc, then runs kube-bench --json-output > kube-bench-report.json || true. When no cluster is reachable the redirect comes up empty and the fixture is copied in, so the report always exists and the flow behaves the same offline and online. entryPoint: [] clears the image entrypoint so the script runs instead of kube-bench install.
  4. parse_report (io.kestra.plugin.scripts.python.Script on python:3.12-slim) reads the JSON, counts total and failed checks, collects the distinct failing control ids, buckets failures by control section with their remediation text, writes the header of remediation-report.md, and emits everything through the outputs protocol.
  5. append_remediation (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) walks the failed control groups, and append_control_note appends one section per group so the report stays ordered and readable.
  6. check_verdict (io.kestra.plugin.core.flow.If) compares failed_count with failed_threshold. Above it, open_remediation_issue (io.kestra.plugin.github.issues.Create) files a labeled issue carrying the control ids and alert_slack posts the counts to Slack. At or below it, log_compliant records the all-clear.
  7. The errors block alerts Slack whenever the scan or the parse breaks, because a dead scanner looks exactly like a clean cluster.

What you get

  • Gateable results: verdict, failed_count, critical_controls, and report_uri are flow outputs any downstream flow can branch on.
  • Escalation where engineers already work: a labeled GitHub issue listing every failing control id, plus a Slack ping with the counts.
  • A remediation report that accumulates one note per failed control group, ready to attach to the issue or an audit evidence pack.
  • An audit trail, every execution clean or not is a dated record with the raw kube-bench JSON kept in internal storage.

Who it's for

  • Platform and SRE teams that must demonstrate CIS Kubernetes Benchmark posture on a schedule.
  • Security engineers who want failing controls turned into tracked work instead of a forgotten report.
  • Kubernetes operators validating a cluster after an upgrade or before an external review.

Why orchestrate this with Kestra

kube-bench is easy to run once and easy to forget. Kestra supplies the loop around it: a disabled-by-default weekly schedule as the safety net, a keyed webhook for on-demand runs, a hermetic container so the tool version lives in the flow file, a threshold branch that separates escalation from the all-clear, execution history with the raw report attached, and routing into GitHub and Slack from one declarative definition. A cron entry on a bastion host gives you none of that, it only audits the cluster someone remembered to run it against.

Prerequisites

  • A worker with Docker access, the scan runs in the kube-bench container and the parser in python:3.12-slim.
  • A reachable Kubernetes API for a real audit. Without one the flow still completes on the bundled fixture, which is exactly what makes it safe to run in CI or on a laptop.
  • A GitHub token that can open issues in github_repository (classic PAT scope repo, or fine-grained Issues: write).
  • A Slack incoming webhook for escalation and for failure alerts.

Secrets

  • KUBEBENCH_WEBHOOK_KEY: key segment guarding the on-demand webhook URL, anyone holding it can trigger an audit.
  • GITHUB_TOKEN: token used to open the remediation issue.
  • SLACK_WEBHOOK_URL: Slack incoming webhook URL.

Quick start

  1. Add the three secrets to your Kestra namespace.
  2. Run the flow once with the default inputs and confirm verdict, failed_count, critical_controls, and report_uri in the outputs.
  3. Point github_repository at a repository where issues are welcome, then re-run with failed_threshold at 0 to watch the fixture failures open the issue and fire the Slack alert.
  4. Trigger on_demand_audit at /api/v1/{tenant}/executions/webhook/{namespace}/kube-bench-cis-benchmark-audit/{KUBEBENCH_WEBHOOK_KEY}, or enable weekly_cis_audit once a cluster is reachable from the worker.

How to extend

  • Audit a fleet by fanning the cluster_name input out with a Loop over a cluster list, one execution per cluster.
  • Pin the benchmark with an extra kube-bench --benchmark flag on the scan task when a specific CIS version must be evidenced.
  • Ship remediation-report.md to S3 or attach it to the GitHub issue as an audit evidence artifact.
  • Turn a breach into a red run by adding io.kestra.plugin.core.execution.Fail under check_verdict.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.