Skip to content

Google Cloud Storage

Scope

Google Cloud Storage (GCS) is GCP's object storage service. Covers bucket storage classes (Standard, Nearline, Coldline, Archive), location types (region, dual-region, multi-region), lifecycle management, versioning, retention policies and bucket lock, IAM-based access vs ACL-based access (and the deprecation of ACLs), uniform bucket-level access (UBLA), public access prevention, signed URLs, customer-managed encryption keys (CMEK), the integration with VPC Service Controls (the GCP data perimeter equivalent), turbo replication, soft delete and the audit characteristics of orphaned buckets and over-permissive bucket policies. Does not cover Filestore (managed NFS, separate service) or Persistent Disk (block storage attached to VMs).

Checklist

  • [Critical] Enable Public Access Prevention at the bucket level for every bucket that does not need to be public. Public Access Prevention is the GCS equivalent of S3 Block Public Access — once enabled, the bucket cannot be made public even by an Owner. The default is "inherited" (off unless the project Org Policy requires it). Set to enforced on every bucket holding internal or sensitive data.
  • [Critical] Enable Uniform Bucket-Level Access (UBLA) on every new bucket. UBLA disables object-level ACLs and forces all access control through IAM, which is the auditable, manageable model. Object-level ACLs are the legacy GCS access model and create the same per-object policy sprawl as S3 ACLs. UBLA cannot be disabled once enabled — choose at bucket creation.
  • [Critical] Use customer-managed encryption keys (CMEK) for any bucket holding sensitive data. The Google-managed key is sufficient for non-regulated workloads only. Configure via defaultKmsKeyName on the bucket; every object inherits the bucket default.
  • [Critical] Use IAM at the bucket level (roles/storage.objectViewer, roles/storage.objectCreator, roles/storage.objectAdmin) rather than at the project level. Project-level grants give access to every bucket in the project, which is too broad. Bucket-level IAM scopes the access to the specific bucket.
  • [Critical] Never grant roles/storage.admin to workload service accounts. The admin role can change bucket policies, lifecycle rules, and IAM bindings — far more than any workload should be able to do. Workloads need only object-level permissions.
  • [Critical] Set a retention policy and bucket lock for any bucket holding regulatory or audit data. Retention policies prevent objects from being deleted before the retention period elapses. Bucket lock makes the retention policy permanent — once locked, the policy can be extended but never shortened. This is the GCS equivalent of S3 Object Lock for compliance regimes that require WORM storage.
  • [Critical] Enable versioning for any bucket where accidental delete or overwrite would be a problem. Versioning is off by default. Once enabled, every object update creates a new version and the previous version is retained. Combine with lifecycle rules to delete old versions after a defined period.
  • [Recommended] Set lifecycle rules to transition objects between storage classes and to delete old objects automatically. Common patterns: Standard → Nearline after 30 days → Coldline after 90 days → Archive after 365 days → Delete after 7 years (or whatever the retention requirement is). Lifecycle rules cut storage cost dramatically for bucket data with a long tail of cold access.
  • [Recommended] Enable bucket access logs by configuring a separate bucket as the log destination. GCS access logs capture every read and write operation against the bucket and are the audit trail for data access. The log destination should be in a separate project (the security tooling project, ideally) with restricted IAM.
  • [Recommended] Use signed URLs for time-bound external access to specific objects, instead of making the bucket public. Signed URLs are generated by the application server with a short expiration time and can be used by external clients to download (or upload) without GCP credentials.
  • [Recommended] Enable soft delete for buckets where accidental deletion would be a problem. Soft delete retains deleted objects for a configurable period (default 7 days, max 90 days), allowing recovery without restoring from backup. Soft delete is on by default for buckets created after October 2024.
  • [Recommended] For multi-region availability, choose dual-region (e.g., nam4 for Iowa + South Carolina) or multi-region (e.g., us for any US region) location. Single-region buckets are subject to single-region outages; multi-region buckets survive single-region failures with automatic replication.
  • [Optional] Enable Turbo Replication on dual-region buckets for any workload requiring sub-15-minute RPO across regions. Turbo Replication is a paid feature that guarantees 100% of objects are replicated within 15 minutes; standard dual-region replication is best-effort.
  • [Optional] Use VPC Service Controls to constrain bucket access to specific VPC perimeters. VPC SC is the GCP equivalent of the AWS data perimeter pattern — it adds a network-layer enforcement on top of IAM, preventing access from outside the configured perimeter even when the IAM grants would otherwise allow it.

Why This Matters

GCS is the foundation for object storage in GCP and is used by nearly every workload. The same kind of misconfigurations that affect S3 in AWS affect GCS in GCP:

  1. Public buckets exposing sensitive data. A bucket that is unintentionally public is the GCS equivalent of the S3 public bucket finding. Public Access Prevention is the fix and should be enforced on every bucket that does not need to be public. Without it, a single misconfigured IAM grant can expose the entire bucket to the internet.

  2. Object-level ACLs creating per-object policy sprawl. ACLs are the legacy GCS access model. They allow per-object permissions, which sound flexible but in practice create thousands of independent permission states that no one can audit. UBLA disables ACLs and is the right answer for any new bucket.

  3. No lifecycle rules on cold data. GCS storage classes have very different costs (Standard $0.020/GB/month vs Archive $0.0012/GB/month). A bucket that holds 10 TB of data that is rarely accessed costs $200/month at Standard and $12/month at Archive — a 16x difference. Without lifecycle rules, data accumulates at the highest cost tier indefinitely.

A secondary failure mode that compounds the first three: bucket policies that grant allUsers or allAuthenticatedUsers. These are the GCP equivalents of granting access to "the entire internet" or "any Google account holder", respectively. Both should be audited and removed unless the bucket is genuinely intended to be public. The audit query is: gcloud storage buckets list --filter="iamConfiguration.publicAccessPrevention!=enforced" followed by checking each result for allUsers or allAuthenticatedUsers in the bucket IAM.

Common Decisions (ADR Triggers)

  • Storage class strategy — Standard for actively-accessed data. Nearline for data accessed less than once per month. Coldline for data accessed less than once per quarter. Archive for data accessed less than once per year. Lifecycle rules transition between classes automatically based on age.
  • Region vs dual-region vs multi-region — region for the lowest cost when single-region availability is sufficient. Dual-region for geographically-diverse durability with named region pairs. Multi-region for the highest availability with automatic placement across multiple regions in a continent.
  • CMEK vs Google-managed encryption — CMEK for regulated and sensitive workloads, with the key in Cloud KMS. Google-managed for non-regulated workloads.
  • UBLA from day one vs migrate later — UBLA from day one is the right answer for every new bucket. Migration of existing buckets requires reviewing every object-level ACL and confirming the equivalent IAM grant exists.
  • Versioning + lifecycle vs no versioning — versioning with lifecycle rules to delete old versions for any bucket where accidental modification is a real risk. No versioning for buckets where the data is regenerated frequently and the old version has no value (e.g., build artifacts).
  • Retention policy + bucket lock — for any bucket holding regulatory data with a retention requirement (HIPAA 6 years, SOX 7 years, financial records 7+ years). Bucket lock makes the retention permanent and is the WORM control for compliance.

Reference Architectures

Data lake with lifecycle management

  • Bucket in us multi-region for cross-region availability
  • UBLA enabled
  • CMEK with key in shared security project
  • IAM:
  • roles/storage.objectCreator to the ingestion service account
  • roles/storage.objectViewer to the analytics team
  • roles/storage.objectAdmin to the platform team only
  • Lifecycle rules:
  • Standard → Nearline after 30 days
  • Nearline → Coldline after 90 days
  • Coldline → Archive after 365 days
  • Delete after 2555 days (7 years)
  • Versioning enabled, with a separate lifecycle rule to delete non-current versions after 30 days
  • Bucket access logs forwarded to the security tooling project

Compliance archive with retention lock

  • Bucket in us-central1 (single region with cross-region replication via Object Replication if needed)
  • UBLA enforced
  • CMEK with key in the compliance project (managed by the compliance team)
  • Retention policy: 2555 days (7 years), bucket-locked
  • Versioning enabled (locked policy applies to all versions)
  • Public Access Prevention: enforced
  • Soft delete: 90 days
  • IAM: read access to the compliance team only; write access via a dedicated service account that only the audit log delivery uses
  • Bucket access logs forwarded to a separate bucket in a different project

Public-facing CDN origin

  • Bucket in us multi-region
  • Public Access Prevention: explicitly disabled (this is the rare case where public access is intentional)
  • Object-level ACLs disabled (UBLA enabled)
  • IAM: roles/storage.objectViewer granted to allUsers for the public-facing prefix only (using a bucket-level IAM condition)
  • Cloud CDN configured with the bucket as the origin
  • Cache-Control headers set on objects to control CDN caching
  • Object names in the public prefix do not contain sensitive identifiers

See Also

  • providers/gcp/storage.md — broader GCP storage service set
  • providers/gcp/kms.md — Cloud KMS for CMEK
  • providers/gcp/iam-organizations.md — IAM model for bucket access
  • providers/gcp/vpc-service-controls.md — data perimeter pattern using VPC Service Controls
  • providers/aws/s3.md — equivalent service in AWS
  • compliance/pci-dss.md — Req 3 (data at rest) and Req 9 (physical access, including media) cite storage controls