Most data leaks from object storage come from public buckets. Google Cloud gives you switches that make that hard to do by accident.
flowchart LR U["Customer browser"] -- "signed URL, 15 min" --> O["Object report.pdf"] B["Bucket gs://dl-reports<br/>uniform access, PAP enforced"] --> O SA["App service account"] -- "objectAdmin" --> B ANY["allUsers"] -. "blocked by PAP" .-> B RP["Retention policy 7 years, locked"] --> B %% step B: The bucket uses uniform bucket-level access (IAM only) and public access prevention. %% step SA: The app’s service account has Storage Object Admin on this bucket only. %% step U: A customer downloads one report through a signed URL that expires after 15 minutes; they need no Google account. %% step O: The object itself is never public. %% step ANY: Even an admin who tries to grant allUsers is blocked by public access prevention. %% step RP: A locked retention policy stops anyone, including owners, from deleting objects before 7 years.
Access control
| Mechanism | Notes |
|---|---|
| IAM on project or bucket | roles/storage.objectViewer, objectCreator, objectUser, objectAdmin, roles/storage.admin |
| Uniform bucket-level access | Turns off object ACLs so IAM is the single source of truth (recommended; required by many org policies) |
| ACLs (fine-grained) | Legacy, per-object; hard to audit |
| Public access prevention | Blocks allUsers/allAuthenticatedUsers on the bucket (or for the whole org via org policy) |
| IAM Conditions | e.g. access only to objects whose name starts with team-a/ |
Signed URLs
A signed URL gives anyone who holds it access to one object for a limited time (up to 7 days with V4 signing), without a Google account. Your backend creates it with a service account’s credentials:
gcloud storage sign-url gs://dl-reports/2026/report.pdf --duration=15m --impersonate-service-account=signer-sa@dl-lab-dev.iam.gserviceaccount.com
Use signed policy documents for browser uploads with size and type limits.
Retention and holds
- Retention policy: objects cannot be deleted or overwritten until they reach a minimum age. Locking the policy (Bucket Lock) makes it permanent: it can be extended, never shortened or removed.
- Object holds (event-based or temporary) block deletion of specific objects until released.
- Object Retention Lock sets retention per object.
Encryption and network controls
- Encrypted at rest by default; CMEK with Cloud KMS if required; CSEK (keys you supply per request) for special cases.
- VPC Service Controls perimeters stop data being copied to buckets outside your organization, even with valid credentials.
- HMAC keys let S3-compatible tools use the XML API; prefer IAM where possible.
| Command | Meaning |
|---|---|
gcloud storage buckets update gs://dl-reports --public-access-prevention |
Enforce PAP |
gcloud storage buckets add-iam-policy-binding gs://dl-reports --member=… --role=roles/storage.objectViewer |
Bucket IAM |
gcloud storage buckets update gs://dl-reports --retention-period=7y |
Retention policy |
Traps: a locked retention policy cannot be removed even by the project owner, and the bucket cannot be deleted while objects are retained; anyone with the signed URL can use it until it expires; object ACLs are ignored once uniform access is on.