Help Center

How to Setup Custom GCP Storage as a Partner

Granting Access for SpinAI Service Account

  1. Create the Bucket

    Before granting access, please make sure the target bucket is configured according to the following requirements:

    • Location: we strongly recommend creating the bucket in the us-central1 region or as a Multi-region bucket in US.
    • Storage class: managed by our platform. No action is required on the client side.
    • Versioning: managed by our platform. Do not enable Object Versioning manually.
    • Object Lifecycle: managed by our platform. Do not configure lifecycle rules manually.
    • Soft delete policy: must be enabled on the bucket with a retention duration of 30 days.

    If a bucket has already been created, make sure it meets the requirements and then you can skip the step of creating a bucket and go to step 2 (Grant Access to the Service Account).

    If the bucket does not yet exist, it can be created in one of three ways. In all examples below, replace BUCKET_NAME with the actual bucket name you want to use.

    Option A — GCP Console

    Steps:

    • Open the Cloud Console (https://console.cloud.google.com/) and make sure the correct project is selected.
    • Navigate to Cloud Storage → Buckets and click Create.
    • Name your bucket: enter BUCKET_NAME.
    • Choose where to store your data:
      • Location type: Region — select us-central1
      • or
      • Location type: Multi-region — select us (United States)
    • Choose a default storage class: leave the default (Standard). It will be managed by our platform.
    • Choose how to control access: leave default settings.
    • Choose how to protect object data:
      • Soft delete policy: set retention duration to 30 days.
      • Object Versioning: leave disabled.
      • Object lifecycle: do not configure any rules.
    • Click Create.

    Option B — gcloud CLI

    Authenticate as a user with sufficient permissions and select the target project:

    gcloud auth login
    gcloud config set project CLIENT_PROJECT_ID

    Create the bucket (regional, us-central1):

    gcloud storage buckets create gs://BUCKET_NAME \
      --location=us-central1 \
      --default-storage-class=STANDARD \
      --uniform-bucket-level-access \
      --soft-delete-duration=30d

    Or, to create a multi-region bucket in US:

    gcloud storage buckets create gs://BUCKET_NAME \
      --location=us \
      --default-storage-class=STANDARD \
      --uniform-bucket-level-access \
      --soft-delete-duration=30d

    Replace BUCKET_NAME with the actual bucket name.

    Note: do not pass --enable-versioning and do not configure --lifecycle-file. These aspects are managed by our platform.

    Option C — Terraform

    Add the following configuration. The bucket name is parameterized via a variable so it can be passed in at apply time.

    terraform {
      required_version = ">= 1.3"
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 5.0"
        }
      }
    }
    
    variable "project_id" {
      type        = string
      description = "GCP project ID where resources will be created"
    }
    
    variable "bucket_name" {
      type        = string
      description = "Name of the GCS bucket to create"
    }
    
    variable "bucket_location" {
      type        = string
      description = "Bucket location: 'us-central1' for a regional bucket or 'US' for a multi-region bucket"
      default     = "us-central1"
    }
    
    provider "google" {
      project = var.project_id
      region  = var.bucket_location
    }
    
    resource "google_storage_bucket" "main" {
      name                        = var.bucket_name
      location                    = var.bucket_location
      storage_class               = "STANDARD"
      uniform_bucket_level_access = true
    
      soft_delete_policy {
        retention_duration_seconds = 2592000 # 30 days
      }
    
      # Versioning and lifecycle are managed by the platform — do not configure here.
      lifecycle {
        prevent_destroy = true
      }
    }

    Apply the configuration:

    terraform plan \
    -var="project_id="gcp-project" -var="bucket_name=BUCKET_NAME"
    
    terraform apply -var="project_id="gcp-project" -var="bucket_name=BUCKET_NAME"

    The terraform.tfstate file is critically important – be sure to back it up in a safe place.

    Notes on the configuration:

    • The lifecycle { prevent_destroy = true } block protects the bucket from accidental destruction. If a future plan would destroy or recreate this resource (for example, due to a state mismatch or a change to an immutable attribute such as name or location), Terraform will refuse to apply and exit with an error. Removing or destroying the bucket would require explicitly removing this protection first.
    • storage_class is set to STANDARD at creation time; ongoing storage class management is handled by Spin platform.
    • No versioning block and no lifecycle_rule blocks are defined — these are managed by our platform.
  2. Grant Access to the Service Account

    You must grant permissions to SpinAI’s service account on the target bucket. The role “Storage Object Admin” allows the SpinAI service account to read, write, and delete objects in the bucket, without granting any control over the bucket itself (its settings, IAM policy, or lifecycle).

    This can be done in one of three ways: via the GCP Console, gcloud, or Terraform.

    Who should perform this: a user in the client’s project who holds the “Storage Admin” or “Owner” role on the project (or on the specific bucket). The “Editor” role is not sufficient, as it does not include permission to modify bucket IAM policies.

    Option A — GCP Console

    Steps:

    • Open the Cloud Console (https://console.cloud.google.com/) and make sure the correct project is selected.
    • Navigate to Cloud Storage → Buckets and select the desired bucket.
    • Go to the Permissions tab and click Grant Access.
    • In the dialog that appears:
      • New principals: add the service account custom-storage-sa@spinbackup-for-work.iam.gserviceaccount.com
      • Select a role: choose Cloud Storage → Storage Object Admin
    • Click Save.

    Option B — gcloud CLI

    Grant the role on the bucket:

    gcloud storage buckets add-iam-policy-binding gs://BUCKET_NAME \
      --member="serviceAccount:gcp-us-b2b-custom-sa-stage@sb-for-work-stage.iam.gserviceaccount.com" \
      --role="roles/storage.objectAdmin"

    Replace BUCKET_NAME with the name of the target bucket.

    Option C — Terraform

    Add the following resource to your Terraform configuration (reusing the bucket_name variable defined above):

    terraform {
      required_version = ">= 1.0"
      required_providers {
        google = {
          source  = "hashicorp/google"
          version = "~> 5.0"
        }
      }
    }
    
    provider "google" {
      project = var.project_id
      region  = var.region
    }
    
    variable "project_id" {
      description = "Project ID GCP"
      type        = string
    }
    
    variable "region" {
      description = "Region GCP"
      type        = string
      default     = "us-central1"
    }
    
    variable "bucket_name" {
      description = "The name of the GCS bucket for which permissions are being granted"
      type        = string
    }
    
    resource "google_storage_bucket_iam_member" "external_sa_object_admin" {
      bucket = var.bucket_name
      role   = "roles/storage.objectAdmin"
      member = "serviceAccount:custom-storage-sa@spinbackup-for-work.iam.gserviceaccount.com"
    }

    Apply the change:

    export GOOGLE_APPLICATION_CREDENTIALS="/path/to/sa-key.json"
    terraform init
    terraform plan -var="project_id=company-project" -var="bucket_name=company-bucket"
    terraform apply -var="project_id=company-project" -var="bucket_name=company-bucket"

    The google_storage_bucket_iam_member resource adds this single binding without affecting any other permissions already configured on the bucket.

    The terraform.tfstate file is critically important – be sure to back it up in a safe place.

  3. Confirm Access Has Been Granted

    Once the bucket has been created and the role has been assigned, please notify us so we can verify access from our side.

Was this helpful?