Read-Only Kubernetes Cost Optimization: How to Find Waste Without Installing Agents
Security-conscious platform teams can discover significant Kubernetes waste using only read-only cluster access — no agents, no cloud credentials, no write permissions required. Here is how the audit-first model works.
The most common reason platform teams delay Kubernetes cost optimization is not cost — it is risk. Deploying an agent to production clusters, granting write access to an external tool, or installing a DaemonSet with node-level permissions introduces operational and security concerns that slow rollout or kill it entirely.
The good news is that finding waste does not require write access. The audit phase — identifying idle workloads, orphaned storage, unused services, and stale namespaces — is entirely possible with read-only Kubernetes API access. You can build a complete picture of what is wasting money before deciding whether to automate cleanup, delegate it to a team, or handle it through a change management process.
This post covers what is discoverable with read-only access, what RBAC it requires, how to run the audit manually, and why the discovery-first model is the right operational approach for infrastructure that cannot afford an incident.
Why Security Teams Push Back on Agent-Based Tools
Agent-based Kubernetes cost tools typically need one or more of the following:
- A DaemonSet deployed on every node for in-pod network traffic analysis
- Cloud provider credentials (IAM roles, service accounts) to pull billing data
- Write permissions to delete or scale resources automatically
- Cluster-admin or equivalent RBAC to enumerate all resource types
These are not unreasonable asks for tools that want to provide full observability and automated optimization. But each requirement adds a security review, an IAM policy approval, or a change management ticket. In organizations with tight cluster security posture, that review cycle can stretch weeks.
The read-only alternative is faster to approve, easier to scope, and produces actionable findings without any of those surface areas. For more on why KorPro does not ask for cloud credentials at all, see why we stopped asking for your cloud credentials.
What RBAC Is Required
A read-only Kubernetes cost audit needs the following permissions — nothing more:
yamlapiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cost-audit-readonly rules: - apiGroups: [""] resources: - pods - services - endpoints - persistentvolumeclaims - persistentvolumes - namespaces - configmaps - secrets - serviceaccounts - nodes verbs: ["get", "list", "watch"] - apiGroups: ["apps"] resources: - deployments - replicasets - statefulsets - daemonsets verbs: ["get", "list", "watch"] - apiGroups: ["batch"] resources: - jobs - cronjobs verbs: ["get", "list", "watch"] - apiGroups: ["networking.k8s.io"] resources: - ingresses verbs: ["get", "list", "watch"] - apiGroups: ["storage.k8s.io"] resources: - storageclasses verbs: ["get", "list", "watch"]
No cloud credentials. No write verbs. No DaemonSet. This role can be scoped to specific namespaces if you want to start with a subset of your cluster before expanding to the full fleet.
What a Read-Only Audit Can Discover
The list of waste categories detectable through the Kubernetes API alone is longer than most teams expect:
| Waste Category | Signal Detectable With Read-Only Access |
|---|---|
| Idle Deployments (0 replicas) | spec.replicas == 0 on Deployment objects |
| Orphaned PVCs | PVC phase is Pending or not referenced by any pod mount |
| Released PVs | PV phase is Released, reclaim policy is Retain |
| Services with no endpoints | Endpoints object with empty subsets |
| LoadBalancer services (actively billed) | spec.type == LoadBalancer + empty endpoints check |
| Unused Ingresses | Ingress with no matching backend service |
| Stale namespaces | Namespace age + no active pods |
| Completed Jobs not garbage-collected | Job status.completionTime set, no ttlSecondsAfterFinished |
| Orphaned ConfigMaps | ConfigMaps not referenced by any pod volume or env |
| Unused Secrets | Secrets not mounted or referenced by any pod |
| Unschedulable pods | Pods stuck in Pending state with no recent events |
| Over-requested containers | Resource requests set; actual usage via metrics-server |
The only major cost driver that requires more than read-only API access is in-pod network traffic — needed for inter-service communication cost analysis. Everything else is fully enumerable through the standard Kubernetes API.
Running a Read-Only Audit Manually
Here is a minimal audit sequence using only kubectl and jq. Every command here runs cleanly with only get and list permissions — nothing is modified.
Step 1 — Identify stale namespaces
bashkubectl get namespaces -o json | \ jq '.items[] | {name: .metadata.name, created: .metadata.creationTimestamp, phase: .status.phase}'
Look for namespaces with naming patterns like pr-*, test-*, staging-v*, or load-* that are older than 30–60 days.
Step 2 — Find PVCs not mounted by any active pod
bash# Collect all PVC names currently mounted by pods kubectl get pods --all-namespaces -o json | \ jq '[.items[].spec.volumes[]? | select(.persistentVolumeClaim != null) | .persistentVolumeClaim.claimName] | unique' \ > /tmp/mounted_pvcs.json # List all PVCs with their phase and size kubectl get pvc --all-namespaces -o json | \ jq '.items[] | {name: .metadata.name, namespace: .metadata.namespace, phase: .status.phase, size: .spec.resources.requests.storage}'
Step 3 — Find services with no active endpoints
bashkubectl get endpoints --all-namespaces -o json | \ jq '.items[] | select(.subsets == null or (.subsets | length == 0)) | {name: .metadata.name, namespace: .metadata.namespace}'
Step 4 — Find Deployments with zero replicas
bashkubectl get deployments --all-namespaces -o json | \ jq '.items[] | select(.spec.replicas == 0) | {name: .metadata.name, namespace: .metadata.namespace}'
Step 5 — Find Released PVs
bashkubectl get pv -o json | \ jq '.items[] | select(.status.phase == "Released") | {name: .metadata.name, capacity: .spec.capacity.storage, storageClass: .spec.storageClassName, reclaimPolicy: .spec.persistentVolumeReclaimPolicy}'
Step 6 — Find Completed Jobs not yet garbage-collected
bashkubectl get jobs --all-namespaces -o json | \ jq '.items[] | select(.status.completionTime != null and .spec.ttlSecondsAfterFinished == null) | {name: .metadata.name, namespace: .metadata.namespace, completed: .status.completionTime}'
These six steps cover the highest-value categories. For deeper ConfigMap and Secret analysis, see how to find and remove orphaned ConfigMaps and finding unused Kubernetes secrets.
An Audit-First CTA Check-In
Before reviewing the rest of this post, if you want to run this across multiple clusters without scripting it manually:
See the KorPro audit workflow — read-only, no agents, results in minutes.
Why Discovery Before Action Is the Right Model
Automated cleanup tools promise to remove manual work from cost optimization. In practice, the clusters where automation is most tempting — production, multi-tenant, shared infrastructure — are also the clusters where automated deletion causes the most incidents.
Common failure modes of automated cleanup:
- Seasonal workloads: A
Deploymentscaled to zero in January for a holiday campaign is not orphaned — it runs every Q4. Automated cleanup would delete it in February. - Crash-looping StatefulSets: A StatefulSet crash-looping because its PVC is missing is a recovery situation, not a cleanup opportunity.
- Shared ConfigMaps: A ConfigMap used by multiple deployments across teams may appear unreferenced if the discovery scope is limited to one namespace.
- PVCs holding archived data: Storage that looks orphaned may hold database snapshots or archived logs that the team has not yet migrated off-cluster.
- GitOps-managed resources: Resources managed by ArgoCD or Flux may be intentionally scaled to zero and will be recreated on the next sync if deleted. See why GitOps doesn't mean clean for details on this class of issue.
The read-only discovery workflow — generate findings, review with owners, act with confidence — protects against all of these. It is slower than automated deletion, but it produces cleanup that does not generate incidents.
Scoping the Audit to Match Your Risk Tolerance
Not every team needs to audit every namespace at once. A practical phased approach:
- Start with non-production namespaces. Lower risk, faster approval cycles, and findings are still meaningful since dev and staging clusters tend to accumulate more waste than production.
- Audit by resource type, not namespace. Running the PVC audit first is fast, high-value, and easy to get owners to approve since storage waste is concrete and measurable.
- Expand to production after establishing a validation workflow. Once the team has a process for reviewing and confirming findings, production audits follow the same steps with higher stakes.
For namespace-level cost attribution, see how to audit Kubernetes costs by namespace.
The KorPro Approach: Read-Only by Default
KorPro's Inspector runs with a read-only ClusterRole. It does not require cloud credentials. It does not deploy a DaemonSet or sidecar. It enumerates resource types across every namespace, identifies unused or orphaned resources, and surfaces them as prioritized findings grouped by estimated savings.
The result is a cluster inventory of waste — not an automated deletion queue. You review findings, confirm ownership, and act when you are confident.
For teams managing multiple clusters, KorPro runs the same audit across all of them without requiring separate credential grants per cluster. See multi-cloud Kubernetes management best practices for context on multi-cluster operational patterns.
See the Audit Workflow
KorPro needs only read-only access to your cluster. No agents, no cloud credentials, no write permissions.
Ready to Clean Up Your Clusters?
KorPro automatically detects unused resources, orphaned secrets, and wasted spend across all your Kubernetes clusters. Start optimizing in minutes.
Related Articles
How MSPs Recover Margin from Unused Kubernetes Resources Across Customer Clusters
MSPs and cloud service providers managing Kubernetes for customers absorb infrastructure waste that erodes margin and complicates billing. Here is how to identify and recover that waste across customer clusters without creating operational risk.
Kubernetes Cost Audit Checklist for EKS, GKE, and AKS
A practical Kubernetes cost audit checklist covering idle workloads, orphaned storage, stale namespaces, and ownership gaps across EKS, GKE, and AKS. Built for platform teams who need to recover real spend.
Kubecost vs KorPro: Which Tool Actually Cleans Up Unused Kubernetes Resources?
Kubecost and KorPro are both part of the Kubernetes cost optimization conversation, but they solve different problems. This breakdown covers unused resource cleanup, audit workflow, storage waste, and operational safety — for buyers actively evaluating tools.
Written by
KorPro Team