0013 - Use an Unconditional Public Object-Reader Binding
Status: Accepted Date: 2026-08-11 Author: Manuel Nucci Supersedes: ADR 0011's public-bucket IAM mechanism only
Context
ADR 0011 keeps a dedicated CDN deferred and serves immutable, non-confidential team logos directly from the public-assets Cloud Storage bucket. Its proposed conditional allUsers binding cannot be applied: Cloud Storage rejects IAM Conditions on a binding for the public principal.
The public access boundary remains narrow. A known logo URL may be fetched, but the bucket must not be listable and private profile media must remain unreachable anonymously. Uniform bucket-level access remains enabled, and the project-level Domain Restricted Sharing exception remains limited to the FPC projects.
Google Cloud Storage documents roles/storage.legacyObjectReader as the IAM equivalent of the object READER role under uniform bucket-level access. It grants storage.objects.get only. In contrast, roles/storage.objectViewer also grants storage.objects.list and would expose bucket enumeration. Cloud Storage IAM roles and uniform bucket-level access document these permissions and the role mapping.
Decision
- Grant
allUsersthe unconditional bucket-levelroles/storage.legacyObjectReaderrole onpublic-assets. - Keep uniform bucket-level access enabled and grant no role that includes
storage.objects.list. - Keep the project-level Domain Restricted Sharing exception required for the public-principal binding. Do not relax the inherited organization policy.
- Keep
private-mediaseparate with public access prevention enforced and no public IAM binding. - Keep opaque, immutable logo keys and
Cache-Control: public, max-age=31536000, immutable. Keep the dedicated CDN, external Application Load Balancer, and custom media hostname deferred under ADR 0011's reconsideration criteria.
This supersedes only ADR 0011's conditional public-bucket binding. ADR 0011's direct-delivery, caching, discovery-authorization, known-object-read, private-media, and DRS-scope decisions remain in force.
Consequences
Positive
- Known public logo objects are readable anonymously without allowing bucket listing.
- The IAM policy uses a documented Cloud Storage role rather than a custom role with equivalent permissions.
- The deployment mechanism is compatible with Cloud Storage's public-principal IAM constraint.
Negative
- The bucket-level grant applies to every object in
public-assets; access cannot be narrowed further with an IAM Condition onallUsers. - Anyone who obtains a logo URL can retrieve its non-confidential contents.
Mitigations
- Store only non-confidential team logos in
public-assets; keep profile media inprivate-mediawith public access prevention enforced. - Use opaque, versioned object keys and avoid confidential data in object paths.
- Test anonymous known-object reads, anonymous bucket-list denial, and anonymous private-media denial whenever the bucket IAM policy changes.