Skip to main content
governance · kubernetes

PersistentVolumeClaims with no storageClassName set

resource types
1
rule IDs covered
3
severity
low

What does ZopNight detect here?

ZopNight flags a Kubernetes PersistentVolumeClaim on EKS, GKE or AKS whose `spec.storageClassName` is empty or missing. Such a claim leaves its storage to whichever default StorageClass the cluster has, or to a hand-made PersistentVolume, so it can sit unbound, or land on a different disk type from the one the team expected.

Signal and threshold

How ZopNight evaluates PersistentVolumeClaims with no storageClassName set.
Field Value
Rule IDsRC-1769 · RC-1869 · RC-1969
Categorygovernance
Severitylow
Metricspec.storageClassName
Thresholdempty or not set
SourceZopNight
Permissions usedlist persistentvolumeclaims · list storageclasses.storage.k8s.io

What an unnamed storage class leaves to chance

The StorageClass named on a claim decides which provisioner creates the disk, which disk type and which reclaim policy the volume gets. When a claim names none, the outcome depends on cluster settings the application team usually does not control. The PersistentVolumes documentation spells out the two cases:

  • A claim with storageClassName: "" can bind only to PersistentVolumes that also have no class. If nobody created such a volume, the claim waits forever.
  • A claim with the field missing is given the cluster’s default StorageClass, when the DefaultStorageClass admission plugin is on and a default exists. If none exists, the field stays unset until one appears; retroactive assignment of a later default is stable since Kubernetes v1.28.

Either way, the disk a team gets can change when a platform team changes the default, and moving a workload to another cluster can leave its claims pending.

Listing claims with no class

Terminal window
kubectl get pvc -A -o json | jq -r '
.items[]
| select((.spec.storageClassName // "") == "")
| "\(.metadata.namespace)/\(.metadata.name) phase=\(.status.phase)"'

To see which StorageClass, if any, is the cluster default, run kubectl get storageclass; the default is marked (default) in the name column.

The single condition behind the finding

ZopNight reads the claim’s storage class name from its collected spec and fires when the value is empty or absent. It treats "" and a missing field the same way. There is no age gate or metric; the check repeats on each evaluation and clears once the claim names a class. Because the admission plugin normally fills the field in at creation, a claim that still shows no class was usually created with "" on purpose or before a default existed.

Limits of the check

The rule does not look at the claim’s phase, so a Bound claim with no class is flagged alongside a pending one. Claims stuck in Pending for other reasons are covered by Unbound PVC. The rule also cannot see whether a classless claim was designed for static provisioning, which is the common false positive.

A governance finding, with no savings figure

This recommendation carries no dollar amount. Its value is predictability: every claim states the storage it needs rather than inheriting it.

Naming the class explicitly

  1. Run kubectl get storageclass and choose the class the workload should use.
  2. Set storageClassName in the claim template of the Deployment, StatefulSet or Helm chart that creates the claim.
  3. For claims already bound, note that the field cannot simply be edited on a live claim; the new value applies to newly created claims.
  4. For static provisioning, keep "" and document it, or give the pre-created volumes and claims a named class so the intent is explicit.
  5. Make sure exactly one StorageClass carries the storageclass.kubernetes.io/is-default-class annotation set to true.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

472 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

472 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·