Help us shape the future of Go! Take the 2026 Go Developer Survey

fleetsweeper

command module
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 1 Imported by: 0

README

The cluster that drifted is the one that pages you at 3am.
Fleetsweeper finds it before it does.

Release Go reference

Fleetsweeper flags the one cluster that drifted from the fleet norm


You run twelve clusters. Or fifty. Or two hundred. They started identical and they did not stay that way. Versions skew. Admission policies drift. Service accounts get patched at 3am and nobody writes it down. Every cluster is "healthy" on its own, so every tool you already own stays quiet. Fleetsweeper finds the one cluster that wandered off the herd.

The fleet itself is the baseline. No rulebook. No rules to write. The modified z-score across your own clusters does the work.

What you walk away with after one scan

  • A Fleet Score from 0 to 100 with a one-line headline you can put on a status TV.
  • The cluster that is most unlike the rest, plus the exact fields that flagged it.
  • Ranked, leverage-weighted recommendations. The fix that takes ten clusters from drifted to clean ranks ahead of the same fix on one.
  • An optional admission webhook that flags pods deviating from your fleet's actual norm, not from a static checklist. It warns by default and never denies until you have read the warnings and opted into enforcement; the rollout path is warn first, enforce on purpose.
  • One unified stream for inbound signal: scan findings, AlertManager, Falco, Trivy CVEs, Kyverno and Gatekeeper PolicyReports.

How scoring works

A scan scores your fleet in two steps.

1. Find the clusters that differ from the rest. Every scanner reports fields per cluster, and each field is compared across the fleet and across each tagged cohort.

  • Numbers (privileged containers, CRD count, pod restarts) use the modified z-score, 0.6745 * (value - median) / MAD. A cluster is flagged when that score passes 3.5 in either direction. The median and MAD come from your own clusters, so one broken cluster cannot widen the band that is meant to catch it.
  • Strings (PSA mode, ingress class) flag every cluster off the most common value, once that value holds at least 60% of the fleet.
  • Lists (installed CRDs) flag a cluster missing any item that at least 60% of the fleet has.

What moves the result:

  • Fleet size. The z-score needs 8 or more clusters. Fleets of 3 to 7 use a stricter leave-one-out rule that flags at most one cluster per field and caps it at warning. Under 3 clusters nothing is flagged, and the report says why.
  • Agreement. A number most clusters share exactly (MAD of zero) is judged like a string. Once one value holds at least 60% of the fleet, every cluster off it is flagged, and the finding reads "every other cluster in the fleet reports exactly 0" instead of quoting a score. A field where no value reaches 60% is skipped. There is no norm to break.
  • Cohorts. A cluster that matches its own tagged cohort (edge sites, say) is not charged for differing from the rest of the fleet.
  • Sensitivity. scan --outlier-threshold and ?threshold= on /api/outliers change the 3.5 cutoff. Lower flags more.

2. Turn what was found into a score. A flagged field becomes a finding. Its severity comes from which field drifted, not from how far. Privileged containers or cluster-admin bindings are critical, node counts are a warning, and most other fields are info. Direction counts too. A cluster on the better side of a field where only one direction is bad (fewer privileged containers than the fleet) is info, titled better than the norm. A finding that restates another one on the same cluster is dropped, so one fact is charged once. The Fleet Score starts at 100 and subtracts:

Cost Points
Each critical, warning, info finding 6, 1.5, 0.25 (capped at 36, 24, 5)
Share of clusters in critical status Up to 20
Share of clusters degraded or strained Up to 10
Kubernetes minor version skew 10 for two or more, 3 for one
Unhealthy nodes in the worst cluster Up to 10

The three largest costs come back as the score's drivers, so the number always arrives with the reason for it.

The details are in Outliers for the detection math, Fleet Score for every cost and cap, and Findings for how severity is chosen.

Consistency is not correctness

The Fleet Score measures one thing: how much your clusters deviate from each other. It is a consistency number, not a correctness number.

That has a specific failure mode, and you should know it before you put the number on a TV. If all fifty of your clusters allow privileged pods, skip resource limits, and run the same end-of-life Kubernetes version, there is no deviation to find. The fleet agrees with itself, so it scores well. A uniformly misconfigured fleet looks the same as a uniformly well-configured one, because the baseline is the fleet, not a standard.

So a Fleet Score of 87 means your clusters mostly agree with each other, and the drivers name the few places they do not. It does not mean they are secure, patched, or compliant with anything. Every score also carries its provenance: how many clusters and scan dimensions produced it, and how many clusters were excluded for insufficient data. A score built from six clusters is a weaker claim than one built from sixty, and the report says which one you are looking at.

A score is also only as good as what the scan could see. A scan that could not observe a cluster says so and is not graded, and a finding is never produced from a read that failed.

Fleetsweeper is therefore not a replacement for policy engines, CIS benchmarks, or vulnerability scanning. Those check clusters against absolute rules, and they are the tools that catch the failure mode above. What they cannot catch is the drift and the one-off snowflake cluster that fleetsweeper exists to find, because nobody wrote a rule for it. Run both: Kyverno or Gatekeeper for the rules you can write down, Fleetsweeper for the anomalies you did not know to write a rule for. The PolicyReport integration feeds their violations into the same finding stream, so the pairing is already wired in.

See it in 30 seconds

go install github.com/dcadolph/fleetsweeper@latest
fleetsweeper serve --demo --addr :8080

Open http://localhost:8080. A synthetic 26-cluster fleet with six days of scan history renders with a 3D globe, findings, drift, outliers, capacity, and a guided tour. No kubeconfig required. The demo is real scan data run through the real engine, so every number on screen is one the engine computed. Auth is off in the demo, so the scan trigger, acks, and tags all work. Real data needs --auth-token. The pulsing red dot is the cinematic part. The outlier detection under it is the real part.

Install for real

kubectl create namespace fleetsweeper
kubectl --namespace fleetsweeper create secret generic fleet-kubeconfig \
  --from-file=config=$HOME/.kube/config
helm install fleetsweeper deploy/helm/fleetsweeper --namespace fleetsweeper \
  --set auth.token=$(openssl rand -hex 32) \
  --set kubeconfig.existingSecret=fleet-kubeconfig \
  --set controller.enabled=true
kubectl apply -f deploy/examples/clusterscan-prod.yaml

The chart pulls the signed ghcr.io/dcadolph/fleetsweeper image and scans every context in the kubeconfig Secret. Without the Secret it scans only the cluster it runs in. The controller reconciles ClusterScan resources and writes outcomes back to .status. Full installation paths in docs/operator/helm.md. Scoped API keys for pipelines in docs/operator/rbac.md.

Why this and not what you already have

You already use What it tells you What Fleetsweeper adds
kubectl, k9s The state of one cluster, right now. A fleet-wide comparison across 24 dimensions. Names the outlier.
Argo CD, Flux Whether each cluster matches its manifest. Drift across clusters even when every cluster matches its own source of truth.
Prometheus, Grafana Time series for what you remembered to instrument. Statistical baselines derived from the fleet, with no rules to write.
OPA, Kyverno Violations against rules you authored. Detects drift you forgot to write a rule for. Complements, does not replace.

Production-ready out of the box

HA backends, leader election, scoped RBAC, audit log, declarative CRDs, Prometheus and OpenTelemetry, signed reports, backups, GitOps integrations, admission webhook, and supply-chain signed images. Full checklist: docs/production-readiness.md.

Where to go next

Start here

Concepts

Operator

Integrations

Reference

Contributing

Issues and PRs welcome. Start with CONTRIBUTING.md and the code of conduct. Security disclosures go through SECURITY.md.

License

MIT. See LICENSE.

Documentation

Overview

Fleetsweeper scans Kubernetes clusters across a fleet and compares them, reporting configuration divergence, outliers, and findings from the CLI or a served dashboard.

Directories

Path Synopsis
Package client is a Go SDK for the Fleetsweeper HTTP API.
Package client is a Go SDK for the Fleetsweeper HTTP API.
Package cmd implements the fleetsweeper command line interface on top of cobra.
Package cmd implements the fleetsweeper command line interface on top of cobra.
internal
admission
Package admission implements the Fleetsweeper ValidatingAdmissionWebhook.
Package admission implements the Fleetsweeper ValidatingAdmissionWebhook.
browser
Package browser holds the dashboard's browser smoke test.
Package browser holds the dashboard's browser smoke test.
cohort
Package cohort partitions a fleet into groups of clusters that look like each other.
Package cohort partitions a fleet into groups of clusters that look like each other.
compare
Package compare produces a structured diff between two Fleetsweeper reports: what changed in the Fleet Score, which findings are new, which resolved, which persisted, and how cluster statuses moved.
Package compare produces a structured diff between two Fleetsweeper reports: what changed in the Fleet Score, which findings are new, which resolved, which persisted, and how cluster statuses moved.
controller
Package controller reconciles ClusterScan custom resources by triggering scans on the configured cadence and writing the outcome back to the resource status.
Package controller reconciles ClusterScan custom resources by triggering scans on the configured cadence and writing the outcome back to the resource status.
cost
Package cost correlates Fleetsweeper findings and per-cluster scores with a user-provided cost CSV.
Package cost correlates Fleetsweeper findings and per-cluster scores with a user-provided cost CSV.
diagnose
Package diagnose runs an end-to-end sanity check across every Fleetsweeper integration.
Package diagnose runs an end-to-end sanity check across every Fleetsweeper integration.
explain
Package explain provides operator-facing explanations for Fleetsweeper findings and scanners.
Package explain provides operator-facing explanations for Fleetsweeper findings and scanners.
fleetdrift
Package fleetdrift converts Fleetsweeper reports into FleetDriftReport Kubernetes custom resources, one per scanned cluster, and writes them to a local directory as YAML files.
Package fleetdrift converts Fleetsweeper reports into FleetDriftReport Kubernetes custom resources, one per scanned cluster, and writes them to a local directory as YAML files.
integration
Package integration contains integration tests that create real Kubernetes clusters using kind.
Package integration contains integration tests that create real Kubernetes clusters using kind.
jsonutil
Package jsonutil centralizes JSON encoding for command output, compact by default and indented on request.
Package jsonutil centralizes JSON encoding for command output, compact by default and indented on request.
kube
Package kube wraps client-go and provides Fleetsweeper's connection helpers for multi-cluster scans, including QPS/burst tuning, a user agent for apiserver audit trails, and concurrent ConnectAll fan-out.
Package kube wraps client-go and provides Fleetsweeper's connection helpers for multi-cluster scans, including QPS/burst tuning, a user agent for apiserver audit trails, and concurrent ConnectAll fan-out.
leader
Package leader provides a thin Kubernetes Lease-based leader election wrapper.
Package leader provides a thin Kubernetes Lease-based leader election wrapper.
logutil
Package logutil ties a structured zap logger to a context.Context so handlers thread the same logger without explicit arguments.
Package logutil ties a structured zap logger to a context.Context so handlers thread the same logger without explicit arguments.
podsec
Package podsec evaluates pod and container security settings with Kubernetes precedence, so every scanner and admission check that asks the same question gets the same answer.
Package podsec evaluates pod and container security settings with Kubernetes precedence, so every scanner and admission check that asks the same question gets the same answer.
policyreport
Package policyreport converts Fleetsweeper findings into PolicyReport CRs using the wgpolicyk8s.io/v1alpha2 schema, the CNCF-standard format consumed by Kyverno, Trivy Operator, Falco Sidekick, and the Policy Reporter UI.
Package policyreport converts Fleetsweeper findings into PolicyReport CRs using the wgpolicyk8s.io/v1alpha2 schema, the CNCF-standard format consumed by Kyverno, Trivy Operator, Falco Sidekick, and the Policy Reporter UI.
remediate
Package remediate turns a Fleetsweeper finding with an inline YAML remediation into a pull request against a GitOps repository.
Package remediate turns a Fleetsweeper finding with an inline YAML remediation into a pull request against a GitOps repository.
report
Package report builds the fleet comparison report from per-cluster scanner results, including divergences, findings, scores, outliers, and trends.
Package report builds the fleet comparison report from per-cluster scanner results, including divergences, findings, scores, outliers, and trends.
scanner
Package scanner defines the Scanner interface, the result and coverage types every scanner returns, and the registry that holds scanners by name.
Package scanner defines the Scanner interface, the result and coverage types every scanner returns, and the registry that holds scanners by name.
scanner/admission
Package admission audits MutatingWebhookConfigurations and ValidatingWebhookConfigurations for two failure modes that silently break clusters: webhooks whose backing service has zero healthy endpoints, and webhooks whose caBundle is expiring soon.
Package admission audits MutatingWebhookConfigurations and ValidatingWebhookConfigurations for two failure modes that silently break clusters: webhooks whose backing service has zero healthy endpoints, and webhooks whose caBundle is expiring soon.
scanner/certs
Package certs scans TLS Secrets, Ingress TLS references, and admission webhook caBundles for upcoming expiry.
Package certs scans TLS Secrets, Ingress TLS references, and admission webhook caBundles for upcoming expiry.
scanner/clusterinfo
Package clusterinfo collects node OS, kernel, container runtime, kubelet and kube-proxy versions and reports drift within a single cluster.
Package clusterinfo collects node OS, kernel, container runtime, kubelet and kube-proxy versions and reports drift within a single cluster.
scanner/crd
Package crd enumerates the CustomResourceDefinitions installed on a cluster and surfaces per-cluster CRD divergence as a scanner result.
Package crd enumerates the CustomResourceDefinitions installed on a cluster and surfaces per-cluster CRD divergence as a scanner result.
scanner/deprecatedapis
Package deprecatedapis identifies in-use API versions that Kubernetes has deprecated or removed.
Package deprecatedapis identifies in-use API versions that Kubernetes has deprecated or removed.
scanner/events
Package events scans the apiserver's recent Event stream and aggregates per-namespace warning counts, surfacing clusters whose signal-to-noise has degraded.
Package events scans the apiserver's recent Event stream and aggregates per-namespace warning counts, surfacing clusters whose signal-to-noise has degraded.
scanner/geo
Package geo locates clusters on Earth from node region/zone labels.
Package geo locates clusters on Earth from node region/zone labels.
scanner/imageaudit
Package imageaudit reports image hygiene across the fleet: digest pinning, latest-tag usage, distinct image counts, and optional registry probes for age and signature checks.
Package imageaudit reports image hygiene across the fleet: digest pinning, latest-tag usage, distinct image counts, and optional registry probes for age and signature checks.
scanner/ingress
Package ingress implements the scanner that lists ingress resources in a cluster.
Package ingress implements the scanner that lists ingress resources in a cluster.
scanner/metrics
Package metrics implements the scanner that reads node resource utilization from the metrics.k8s.io API.
Package metrics implements the scanner that reads node resource utilization from the metrics.k8s.io API.
scanner/namespace
Package namespace implements the scanner that lists namespaces in a cluster.
Package namespace implements the scanner that lists namespaces in a cluster.
scanner/networkpolicy
Package networkpolicy implements the scanner that collects NetworkPolicy data from a cluster.
Package networkpolicy implements the scanner that collects NetworkPolicy data from a cluster.
scanner/nodehealth
Package nodehealth implements the scanner that checks node health conditions.
Package nodehealth implements the scanner that checks node health conditions.
scanner/policyreportingest
Package policyreportingest reads wgpolicyk8s.io PolicyReport and ClusterPolicyReport custom resources written by other tools (Kyverno, Gatekeeper, Trivy, kube-bench) and aggregates their fail/warn results per cluster.
Package policyreportingest reads wgpolicyk8s.io PolicyReport and ClusterPolicyReport custom resources written by other tools (Kyverno, Gatekeeper, Trivy, kube-bench) and aggregates their fail/warn results per cluster.
scanner/quota
Package quota inspects ResourceQuota and LimitRange coverage across namespaces.
Package quota inspects ResourceQuota and LimitRange coverage across namespaces.
scanner/rbac
Package rbac scans the cluster's RBAC graph (ClusterRoles, RoleBindings, ServiceAccounts) and flags wildcard permissions and over-broad bindings.
Package rbac scans the cluster's RBAC graph (ClusterRoles, RoleBindings, ServiceAccounts) and flags wildcard permissions and over-broad bindings.
scanner/rbacaudit
Package rbacaudit implements the scanner that audits RBAC for over-permissive bindings and rules.
Package rbacaudit implements the scanner that audits RBAC for over-permissive bindings and rules.
scanner/resources
Package resources implements the scanner that collects node capacity and condition data.
Package resources implements the scanner that collects node capacity and condition data.
scanner/security
Package security audits security-affecting workload configuration: PodSecurityStandards labels, default-deny NetworkPolicy presence, and similar fleet-wide hardening signals.
Package security audits security-affecting workload configuration: PodSecurityStandards labels, default-deny NetworkPolicy presence, and similar fleet-wide hardening signals.
scanner/service
Package service implements the scanner that lists services in a cluster.
Package service implements the scanner that lists services in a cluster.
scanner/version
Package version reports the Kubernetes server version from each cluster and detects fleet-wide skew.
Package version reports the Kubernetes server version from each cluster and detects fleet-wide skew.
scanner/vulnerabilities
Package vulnerabilities reads aquasecurity.github.io/v1alpha1 VulnerabilityReport custom resources produced by the Trivy Operator and aggregates their severity counts into a per-cluster baseline.
Package vulnerabilities reads aquasecurity.github.io/v1alpha1 VulnerabilityReport custom resources produced by the Trivy Operator and aggregates their severity counts into a per-cluster baseline.
scanner/workloadcoverage
Package workloadcoverage reports on PDB and HPA coverage of replicated workloads.
Package workloadcoverage reports on PDB and HPA coverage of replicated workloads.
scanner/workloadsec
Package workloadsec implements the scanner that audits pod security contexts across all namespaces.
Package workloadsec implements the scanner that audits pod security contexts across all namespaces.
seal
Package seal provides HMAC-SHA256 sealing for export bundles.
Package seal provides HMAC-SHA256 sealing for export bundles.
server
Package server serves the fleetsweeper HTTP API and the embedded web dashboard backed by the scan store.
Package server serves the fleetsweeper HTTP API and the embedded web dashboard backed by the scan store.
store
Package store persists scans, results, and related fleet records in SQLite or Postgres.
Package store persists scans, results, and related fleet records in SQLite or Postgres.
testcerts
Package testcerts generates self-signed X.509 certificates for tests that exercise certificate parsing and expiry logic.
Package testcerts generates self-signed X.509 certificates for tests that exercise certificate parsing and expiry logic.
tracing
Package tracing wires up an OpenTelemetry tracer provider configured by the standard OTEL_EXPORTER_OTLP_ENDPOINT environment variable.
Package tracing wires up an OpenTelemetry tracer provider configured by the standard OTEL_EXPORTER_OTLP_ENDPOINT environment variable.
util
Package util holds small helpers shared across packages so a single implementation is imported everywhere rather than duplicated.
Package util holds small helpers shared across packages so a single implementation is imported everywhere rather than duplicated.
webhooks
Package webhooks loads a YAML config of outbound HTTP subscribers and dispatches matching findings to each one after every scan.
Package webhooks loads a YAML config of outbound HTTP subscribers and dispatches matching findings to each one after every scan.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL