GCS buckets with object versioning turned off
What does ZopNight detect here?
Object versioning left off a GCS bucket means every overwrite or delete is immediate and permanent. ZopNight's rule RC-141 fires when the discoverer records versioning_enabled as anything but true on an enriched bucket. The result is a $0, low-severity finding aimed at recoverability rather than cost.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-141 |
| Category | compliance |
| Severity | low |
| Metric | none — pure configuration read |
| Source | bucket_versioning.go |
Where it applies
Deletes in GCS are final by default
Without versioning, Cloud Storage keeps exactly one generation of each object. A PUT to an
existing name destroys the previous bytes in the same instant it writes the new ones; a
DELETE leaves nothing to restore from. The classic incidents are mundane, not malicious: a
sync job pointed at the wrong prefix, a lifecycle rule broader than intended, a script
cleaning “temp” files that were not temp. Versioning changes the failure mode: the old
generation becomes noncurrent instead of gone, and recovery is a copy operation rather than
a support ticket that ends in “the data is unrecoverable.”
What versioning does and does not protect
Versioning is protection against mistakes, not against attackers, and it is worth being
precise about the boundary. A principal with delete permission can also delete noncurrent
generations, so versioning alone is not a ransomware defense; a retention policy or Bucket
Lock covers the adversarial case. Versioning also is not a backup: everything still lives in
one bucket, one project, one region. What it reliably buys you is an undo button for the
most common data-loss event in object storage, at the cost of storing noncurrent generations
until a lifecycle rule expires them. Pair it with a numNewerVersions-based lifecycle
condition so the safety net does not become an unbounded storage bill.
Detection reads one flag, and fails safe
The GCP discoverer derives versioning_enabled from the bucket’s versioning.enabled field
and writes both polarities into metadata. The rule fires when the value is anything other
than true (an explicit false and an absent key are treated identically), but only on
resources that carry the storage_class key the same enricher always stamps. That gate
means a bucket discovery never enriched is skipped, not flagged; the rule abstains on
unknowns. Enrichment is read-only (storage.buckets.get), and remediation is never
automated.
Check and enable in two commands
gcloud storage buckets describe gs://BUCKET --format="value(versioning.enabled)"gcloud storage buckets update gs://BUCKET --versioningAnything other than True from the first command reproduces the finding. Enabling
versioning is instant, takes no downtime, and affects only writes that happen afterwards.
That is one more reason to turn it on before you need it rather than after.