Cluster Guardian

Cluster Guardian is an open-source tool that analyzes Kubernetes clusters and provides actionable recommendations for improving reliability, security, performance, and operational efficiency.
✔ Cluster: production
⚠ Namespace: payments
• 5 Pods missing resource requests
• 2 CrashLoopBackOff containers
• Deployment "api" uses :latest tag
• Missing HorizontalPodAutoscaler
⚠ Security
• 8 containers running as root
• 3 namespaces without NetworkPolicies
⚠ Monitoring
• 4 Services are not scraped by Prometheus
• Missing alerts for Redis and PostgreSQL
💰 Optimization
• Estimated CPU overprovisioning: 68%
• Estimated Memory overprovisioning: 41%
Features
- Cluster health analysis
- Workload validation (Deployments, StatefulSets, DaemonSets, Jobs, CronJobs)
- Resource optimization using Prometheus metrics
- Detection of unhealthy workloads (CrashLoopBackOff, Pending, ImagePullBackOff, OOMKilled, restart storms)
- Identification of missing CPU/Memory requests and limits
- Readiness, Liveness, and Startup Probe validation
- PodDisruptionBudget coverage and topology spread validation
- Unused resource detection (ConfigMaps, Secrets, PVCs, Services without pods, dangling Ingress/HPA/PDB targets)
- TLS certificate checks (Ingress certificates near expiry, missing TLS secrets, cert-manager Certificate readiness)
- Deprecated API detection (kubent-style, severity based on the cluster's version)
- Security checks (root containers, privileged pods, dangerous capabilities, host namespaces, RBAC, Network Policies)
- Pod Security Standards compliance summary (
--framework pss shows only PSS-mapped findings)
- Monitoring validation (Prometheus, Alertmanager, ServiceMonitors, PodMonitors, PrometheusRules)
- Argo CD / Flux health integration
- Cost optimization recommendations
- Automatic cluster documentation generation
- Cluster health score (0–100) and A–F grades, with
--fail-below gating
- Fleet mode: hosted multi-cluster scorecard with declarative, Secret-based cluster registration
- Export reports in JSON, Markdown, and HTML
- REST API and Web Dashboard
- CLI for automation and CI/CD integration
Installation
go install github.com/AndrewKarpaty/cluster-guardian@latest
Or build from source:
git clone https://github.com/AndrewKarpaty/cluster-guardian.git
cd cluster-guardian
go build -o cluster-guardian .
Docker
docker build -t cluster-guardian .
# CLI: analyze using your local kubeconfig
docker run --rm -v ~/.kube:/kube:ro -e KUBECONFIG=/kube/config cluster-guardian
# Dashboard: bind to 0.0.0.0 so the published port is reachable
docker run --rm -p 8080:8080 -v ~/.kube:/kube:ro -e KUBECONFIG=/kube/config \
cluster-guardian serve --listen 0.0.0.0:8080
When running in-cluster (e.g. as a Deployment for the dashboard), no kubeconfig is needed — the ServiceAccount token is picked up automatically.
Helm
A chart lives in charts/cluster-guardian. It ships the read-only ClusterRole, health probes, a NetworkPolicy (on by default), and hardened pod defaults that pass cluster-guardian's own checks:
helm install cluster-guardian ./charts/cluster-guardian \
--namespace cluster-guardian --create-namespace \
--set persistence.enabled=true \ # keep trend history on a PVC
--set fleet.enabled=true # multi-cluster scorecard mode
Key values: prometheusUrl, ingress.* (or httpRoute.* for Gateway API), persistence.*, fleet.*, serviceMonitor.*, rbac.includeSecrets (disable to run without cluster-wide Secret read access; the affected checks skip). See values.yaml for the full list.
Usage
Analyze the cluster from your current kubeconfig context:
cluster-guardian
Common options:
cluster-guardian analyze \
--context production \ # kubeconfig context
-n payments -n checkout \ # limit to specific namespaces
--prometheus-url http://localhost:9090 \ # enable usage-based cost analysis
--verbose # show remediation hints for each finding
If Prometheus is not exposed outside the cluster, port-forward it first:
kubectl port-forward -n monitoring svc/prometheus-operated 9090:9090
cluster-guardian --prometheus-url http://localhost:9090
Export reports
cluster-guardian analyze -o json --output-file report.json
cluster-guardian analyze -o markdown --output-file report.md
cluster-guardian analyze -o html --output-file report.html
Cluster documentation (deprecated)
The docs command (Markdown documentation of workloads, services, and
ingresses) is deprecated and will be removed in the release after next —
cluster documentation is out of scope for an analyzer. See
#52.
Web dashboard and REST API
cluster-guardian serve --listen 127.0.0.1:8080
The dashboard supports filtering by severity and namespace, free-text search,
collapsible sections, an auto-refresh toggle, and JSON/Markdown download
buttons. Filtering and search also work in -o html file exports.
Each analysis run is recorded in a history, powering a trend chart (findings
by severity over time) and a "since previous run: N new, M resolved" diff in
the dashboard. Pass --history-dir /path to persist history across restarts
(use a PVC when running in-cluster); without it history is in-memory only.
--history-limit caps the number of retained runs (default 100).
| Endpoint |
Description |
GET / |
Web dashboard (HTML report) |
GET /api/report |
Report as JSON (?refresh=true bypasses cache) |
GET /api/report/markdown |
Report as Markdown |
GET /api/history |
History index: time + severity counts per run |
GET /api/history/diff |
New and resolved findings vs the previous run |
GET /metrics |
Prometheus metrics: findings, score, run stats |
GET /healthz |
Liveness probe |
Prometheus metrics
serve exposes the guardian's own metrics at /metrics, rendered from the
cached report (scraping never triggers an analysis): findings as
cluster_guardian_findings{cluster,section,namespace,severity}, the health
score, and per-run timestamp, duration and error counters — in fleet mode one
series set per registered cluster. Alert on them with your existing stack:
- alert: ClusterGuardianCriticalFindings
expr: sum by (cluster) (cluster_guardian_findings{severity="critical"}) > 0
- alert: ClusterGuardianScansStale
expr: time() - cluster_guardian_last_run_timestamp_seconds > 3600
With the Helm chart, --set serviceMonitor.enabled=true creates a
ServiceMonitor (requires the Prometheus Operator).
Fleet mode: hosted multi-cluster scorecard
Run cluster-guardian in a cluster and let it scan your whole fleet on a
schedule, SecurityScorecard-style — every cluster gets a 0–100 health score
and an A–F grade:
cluster-guardian serve --fleet --fleet-interval 5m --history-dir /data
The cluster add helper registers a cluster in one step — it provisions a
read-only ServiceAccount (with a ClusterRole scoped to exactly the resources
cluster-guardian reads) and a long-lived token on the target cluster, then
stores the connection details on the hub:
cluster-guardian cluster add prod --remote-context prod-admin
Re-running it refreshes the ClusterRole rules and rotates the stored
credentials. Use --server when the kubeconfig URL is not reachable from
inside the hub cluster.
Alternatively, register clusters declaratively: create a Secret in the
tool's namespace labeled cluster-guardian.io/secret-type: cluster with
name, server, and a config JSON holding a bearer token for a read-only
ServiceAccount on the target cluster:
apiVersion: v1
kind: Secret
metadata:
name: cluster-prod
labels:
cluster-guardian.io/secret-type: cluster
stringData:
name: prod
server: https://prod.example.com:6443
config: |
{"bearerToken": "<token>", "tlsClientConfig": {"caData": "<base64 CA>"}}
The local cluster is always included automatically.
The root page becomes the fleet overview (grade, score, and top counts per
cluster); each card links to that cluster's full dashboard with its own
trends. Per-cluster API routes: /api/clusters,
/api/clusters/{name}/report, /api/clusters/{name}/history (+/diff).
One unreachable cluster never stalls the rest: scans run concurrently with a
per-cluster timeout, and failures surface on the cluster's card. Security
note: a fleet instance holds credentials for every registered cluster —
restrict its namespace with RBAC and NetworkPolicies, and grant target
ServiceAccounts only view-level access.
CI/CD integration
Use --fail-on to gate pipelines on findings:
cluster-guardian analyze --fail-on critical # exit code 3 on critical findings
cluster-guardian analyze --fail-on warning # exit code 2 on warnings or worse
cluster-guardian analyze --fail-below 80 # exit code 2 if the health score drops below 80
Every report carries a 0–100 health score and A–F grade (severity-weighted),
shown in the terminal header, dashboard, and JSON summary.
Checks
| Area |
What is checked |
| Workloads |
Missing resource requests/limits, :latest tags, missing probes, single replicas, missing HPAs, missing or drain-blocking PodDisruptionBudgets, missing topology spread |
| Health |
CrashLoopBackOff, ImagePullBackOff, Pending pods, OOMKilled containers, restart storms |
| Security |
Root/privileged containers, dangerous capabilities, host network/PID/IPC, missing seccomp profiles, writable root filesystems, ServiceAccount token automounting, Secrets in env vars, namespaces without PSS enforcement labels or NetworkPolicies, wildcard ClusterRoles, cluster-admin ServiceAccounts; findings are tagged with Pod Security Standards controls and summarized per framework |
| Monitoring |
Prometheus/Alertmanager presence, ServiceMonitor scrape coverage, missing alerts for Redis, PostgreSQL, Kafka, and other stateful services |
| Hygiene |
Unused ConfigMaps and Secrets, unmounted or unbound PVCs, Services matching no pods, Ingress paths to missing Services, HPAs targeting missing workloads, PDBs selecting nothing |
| Certificates |
Ingress TLS certificates expiring within 30 days (critical under 7), Ingresses referencing missing TLS secrets, cert-manager Certificates not Ready |
| Deprecations |
Objects still written with deprecated API versions (from managedFields / last-applied), critical when the API is removed in the next minor version or earlier |
| GitOps |
Argo CD Application health and sync status, Flux Kustomization/HelmRelease readiness |
| Optimization |
CPU and memory overprovisioning, estimated from requests vs. actual usage in Prometheus |
System namespaces (kube-system, etc.) are skipped by default; include them with --include-system.
Requirements
- Kubernetes 1.25+ with read-only access (a
view-like ClusterRole covers most checks; RBAC checks additionally need read access to ClusterRoles and ClusterRoleBindings, and Secret hygiene checks need list access to Secrets — only names and types are read, secret data is never held. Checks whose resources are not readable are skipped silently.)
- Optional: Prometheus for usage-based optimization checks
- Optional: Prometheus Operator, Argo CD, Flux, or cert-manager CRDs — detected automatically
License
MIT — see LICENSE.