StorageClasses that do not allow volume expansion
What does ZopNight detect here?
ZopNight flags a Kubernetes StorageClass on EKS, GKE or AKS whose `allowVolumeExpansion` is `false` or left unset. Kubernetes expands a PersistentVolumeClaim only when its class sets that field to `true`, so every volume created from such a class is stuck at its original size and growing it later means copying data to a new, larger volume.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1781 · RC-1881 · RC-1981 |
| Category | governance |
| Severity | low |
| Metric | allowVolumeExpansion |
| Threshold | false or not set |
| Source | ZopNight |
| Permissions used | list storageclasses.storage.k8s.io |
Where it applies
Why a fixed-size class becomes a migration later
Databases, queues and log stores grow. On a class that allows it, growing a volume is a one-line
change: edit the claim’s requested size and the volume behind it is expanded in place. The
PersistentVolumes documentation
is explicit that you can only expand a PVC if its storage class’s allowVolumeExpansion field is
set to true, and that no new PersistentVolume is created in the process.
On a class that forbids it, the same request is refused. The team is left to provision a larger claim, copy the data across and cut the workload over, which is downtime and risk for a problem that should have been routine. Expansion only ever grows a volume; Kubernetes does not support shrinking a claim below its current size.
Finding classes that block resizing
kubectl get storageclass -o json | jq -r ' .items[] | select(.allowVolumeExpansion != true) | "\(.metadata.name) provisioner=\(.provisioner) allowVolumeExpansion=\(.allowVolumeExpansion)"'Then see which claims depend on each one:
kubectl get pvc -A -o json | jq -r ' .items[] | select(.spec.storageClassName == "<class-name>") | "\(.metadata.namespace)/\(.metadata.name) \(.spec.resources.requests.storage)"'Anything other than true
ZopNight reads the field from the StorageClass it collected and fires when expansion is not
enabled. A class that omits allowVolumeExpansion is recorded as false, so an unset field is
flagged the same way as an explicit false, which matches Kubernetes, where only true permits
expansion. There is no metric or window. The check does not look at the claims using the class,
so a class with no claims at all is flagged the same as one backing a busy database.
What the check cannot see
The rule does not know whether the provisioner is able to expand volumes. The storage classes page lists expansion support by volume type, with CSI volumes supported from Kubernetes 1.24, but the CSI driver itself must implement it.
Governance, not savings
This low-severity finding has no dollar figure. Its benefit is avoiding a future data migration and the temptation to over-provision disks up front just in case, which costs money from day one.
Enabling expansion on the class
- Confirm the provisioner supports volume expansion in its own documentation.
- Patch the class in place:
kubectl patch storageclass <name> -p '{"allowVolumeExpansion": true}'. Unlike the provisioner, parameters, reclaim policy and binding mode, this field is not immutable. - Test on a non-critical claim by raising
spec.resources.requests.storageand watchingkubectl describe pvcfor the resize events. - Record the change in the manifest or chart that owns the StorageClass so a redeploy does not revert it.
A related setting on the same object is covered by StorageClass uses immediate binding.