Uniform Bucket-Level Access vs ACLs: When to Migrate GCS Buckets and How to Validate
Decide between GCS Uniform Bucket-Level Access and fine-grained ACLs. Compare models, trade-offs, and validate migration with gsutil and gcloud checks.
10 Feb 2026, 03:11 UTC

The decision you actually face
You have a Cloud Storage bucket that mixes IAM grants with object ACLs, and an audit or new service requires a single source of truth for access. The practical question is not whether Uniform Bucket-Level Access is better in theory, it is whether your workloads can tolerate moving from fine-grained ACLs to IAM-only control without breaking writes, presigned URLs, or cross-project sharing.
Uniform Bucket-Level Access replaces per-object ACLs with IAM-only permissions on the bucket. Fine-grained ACLs allow bucket, object, and canned ACL grants like allUsers or projectEditors on individual objects. New buckets default to uniform mode in most projects, but existing buckets often remain in fine-grained mode for backward compatibility.
Constraints that drive the choice
- Applications that call
storage.objects.updatewith ACLs or use canned ACLs on upload will fail in uniform mode. - Presigned URLs continue to work in uniform mode when granted via IAM, but ACL-based signed URLs require migration to IAM.
- Cross-project access is cleaner with IAM, but legacy transfers may still carry ACL grants unless converted.
- Uniform mode is required for certain features and recommended posture, while fine-grained mode is supported but not recommended for new designs.
Options compared
| Aspect | Uniform Bucket-Level Access | Fine-grained ACLs |
|---|---|---|
| Access control model | IAM only at bucket level. Object ACLs are ignored. | IAM + ACLs per bucket and per object. |
| Management surface | Single IAM policy per bucket. Simpler auditing. | Bucket IAM plus ACLs on each object. Higher sprawl. |
| Default for new buckets | Enabled by default in new projects. | Requires explicit opt-in. |
| Compatibility | Breaks code that sets or reads object ACLs. | Backward compatible with legacy apps. |
| Migration path | gsutil uniformbucketlevelaccess set on bucket. Existing ACLs are translated to IAM for read compatibility. | No migration needed. |
Trade-offs
Uniform mode simplifies permission reviews and aligns with organization policies. You get one IAM policy to inspect, no hidden allUsers grants on individual objects, and consistent enforcement for Data Access audit logs.
The cost is compatibility. Any service that writes objects with acl=projectPrivate or that queries storage.objects.getIamPolicy expecting ACLs will see different behavior. Cross-project sharing that relied on ACL grants must be re-expressed as IAM bindings. Migration is one-way in practice for active workloads because disabling uniform mode re-exposes ACLs and can reintroduce drift.
Validate current mode before changing
Run from a workstation with Cloud SDK installed and a principal that has storage.buckets.get.
gsutil getbucketinfo gs://my-bucketCheck the JSON for UniformBucketLevelEnabled. True means uniform mode is active, False means fine-grained.
Then inspect effective IAM:
gcloud storage iam policy get gs://my-bucket --format=jsonMap bindings to expected principals. This is the source of truth in uniform mode.
Concrete migration steps
Run these from a terminal with roles/storage.admin or storage.buckets.update on the target bucket.
- Confirm no active ACL writes. Search logs for
storage.objects.updatewith ACL changes in the last 30 days. - Enable uniform bucket-level access:
gsutil uniformbucketlevelaccess set on gs://my-bucketThe command updates bucket metadata. Existing ACLs are preserved for read compatibility but no longer enforce access.
- Replicate required grants as IAM bindings. Example to grant read to a group:
gcloud storage buckets add-iam-policy-binding gs://my-bucket \
--member="group:[contact removed]" \
--role="roles/storage.objectViewer"Required permission: storage.buckets.setIamPolicy.
- Verify the change:
gsutil getbucketinfo gs://my-bucketExpect UniformBucketLevelEnabled to be True in the returned JSON.
gcloud storage iam policy get gs://my-bucket --format=jsonConfirm the bindings you added are present and no unexpected principals remain.
Limitations and rollback
Uniform mode cannot be partially enabled per prefix. All objects inherit bucket IAM. Object-level conditions are not supported.
If you need to revert, you can disable uniform mode:
gsutil uniformbucketlevelaccess set off gs://my-bucketThis re-enables fine-grained ACL evaluation. Use with caution because re-enabling ACLs can restore previously hidden grants. Required permission: storage.buckets.update.
Practical check after migration: attempt a write from a test service account that has only bucket IAM roles/storage.objectCreator. The write should succeed and the object should be readable only by principals granted via bucket IAM, not via legacy object ACLs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.