Back to Blog
Cost Optimization

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.

KorPro Team
May 6, 2026
8 min read
KubernetesCost OptimizationSecurityAuditPlatform EngineeringDevOpsSRE

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:

yaml
apiVersion: 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 CategorySignal Detectable With Read-Only Access
Idle Deployments (0 replicas)spec.replicas == 0 on Deployment objects
Orphaned PVCsPVC phase is Pending or not referenced by any pod mount
Released PVsPV phase is Released, reclaim policy is Retain
Services with no endpointsEndpoints object with empty subsets
LoadBalancer services (actively billed)spec.type == LoadBalancer + empty endpoints check
Unused IngressesIngress with no matching backend service
Stale namespacesNamespace age + no active pods
Completed Jobs not garbage-collectedJob status.completionTime set, no ttlSecondsAfterFinished
Orphaned ConfigMapsConfigMaps not referenced by any pod volume or env
Unused SecretsSecrets not mounted or referenced by any pod
Unschedulable podsPods stuck in Pending state with no recent events
Over-requested containersResource 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

bash
kubectl 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

bash
kubectl 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

bash
kubectl get deployments --all-namespaces -o json | \ jq '.items[] | select(.spec.replicas == 0) | {name: .metadata.name, namespace: .metadata.namespace}'

Step 5 — Find Released PVs

bash
kubectl 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

bash
kubectl 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 Deployment scaled 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:

  1. 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.
  2. 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.
  3. 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.

Create your free KorPro account | Contact our team

Stop Wasting Kubernetes Resources

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.

Written by

KorPro Team

View All Posts