GCS buckets still using per-object ACLs instead of uniform access
What does ZopNight detect here?
Uniform bucket-level access replaces per-object ACLs with IAM alone; with it off, 2 permission systems answer "who can read this object" and audits must check both. ZopNight raises medium-severity RC-1232 when the discoverer does not record uniform_bucket_level_access_enabled=true on an enriched bucket. Enabling it stays reversible for 90 days.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1232 |
| Category | compliance |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | bucket_uniform_access.go |
Where it applies
Two permission systems on one bucket
With uniform bucket-level access disabled, a GCS bucket answers access questions through two
independent mechanisms: IAM policies on the bucket, and legacy ACLs that can differ on every
single object. The practical consequence is that no bucket-level review is conclusive. You
can audit the IAM policy, find it perfectly scoped, and still have one object among millions
carrying a READER ACL for allUsers, granted years ago by a tool that defaulted to
object-level sharing. Every exposure investigation then becomes an object-by-object walk,
and every access-control statement to an auditor has to be hedged with “plus whatever the
ACLs say.”
Uniform access removes the second system. ACLs stop being evaluated, IAM becomes the single source of truth, and “who can access this bucket” is once again a question with one answer. Google recommends it for new buckets, and Public Access Prevention composes cleanly with it: PAP blocks public IAM grants, uniform access guarantees there is no ACL side channel left to check.
Migration risk is real but bounded
The one legitimate reason to hesitate is a workload that actually depends on per-object ACLs, typically multi-tenant patterns where each object is shared with a different principal. Enabling uniform access on such a bucket breaks those reads. Two things bound the risk: Cloud Audit Logs can show whether ACL-dependent access is happening at all, and the switch is reversible for 90 days after enabling, so a mistake is recoverable rather than fatal. After 90 days the ACL data is gone and the change is permanent. Migrate the sharing model to IAM conditions or separate prefixes first, then flip the switch.
One field to check, one flag behind the finding
gcloud storage buckets describe gs://BUCKET \ --format="value(uniform_bucket_level_access)"False (or empty) reproduces what ZopNight saw. The discoverer derives the signal from
iamConfiguration.uniformBucketLevelAccess.enabled and writes
uniform_bucket_level_access_enabled=true into metadata only when it is on, never an
explicit false. The rule fires when the key is missing on a bucket that carries the
storage_class anchor stamped by the same enricher; without that anchor the resource is
treated as un-enriched and skipped. Reading the configuration requires only
storage.buckets.get; flipping the setting is a deliberate, human gcloud storage buckets update gs://BUCKET --uniform-bucket-level-access. Nothing in ZopNight changes bucket
security posture automatically.