GCP Cloud Storage Event

This guide will help you set up GCP Cloud Storage event notifications using Terraform Infrastructure as Code.

Prerequisites

  • GCP Project with billing enabled

  • gcloud CLI installed

  • Terminal/Command Line access

  • Owner or Editor role in the GCP project


Step 1: Install Required Tools

1.1 Install gcloud CLI

Check if already installed:

gcloud --version

For macOS:

curl https://sdk.cloud.google.com | bash
exec -l $SHELL

For Linux:

curl https://sdk.cloud.google.com | bash
exec -l $SHELL

For Windows: Download from: https://cloud.google.com/sdk/docs/install


1.2 Install Terraform

For macOS:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform

For Linux:

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

For Windows: Download from: https://www.terraform.io/downloads

Verify installation:

terraform --version

Step 2: Authenticate with GCP

2.1 Initialize gcloud

gcloud init

This will guide you through:

  • Logging in to your Google account

  • Selecting your GCP project

  • Setting default compute region/zone


2.2 Login to GCP

gcloud auth login

This will open your browser for authentication.


2.3 Set Application Default Credentials

gcloud auth application-default login

This allows Terraform to authenticate with GCP.


2.4 Set Your Project

List available projects:

gcloud projects list

Set the project you want to use:

gcloud config set project YOUR_PROJECT_ID

2.5 Verify Current Project

gcloud config get-value project

Step 3: Create Terraform Configuration Files

3.1 Create Project Directory

mkdir gcp-event-notification-setup
cd gcp-event-notification-setup

3.2 Create Main Terraform Configuration

Create a file named main.tf with the following content:

terraform {
  required_version = ">= 1.0"
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

# Variables for customization
variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  description = "GCP Region for resources"
  type        = string
  default     = "us-central1"
}

variable "service_account_name" {
  description = "Name for the service account"
  type        = string
  default     = "event-subscription-service"
}

variable "custom_role_id" {
  description = "ID for the custom IAM role"
  type        = string
  default     = "gcs_event_notification_manager"
}

variable "custom_role_title" {
  description = "Title for the custom IAM role"
  type        = string
  default     = "GCS Event Notification Manager"
}

# Enable required APIs
resource "google_project_service" "required_apis" {
  for_each = toset([
    "cloudresourcemanager.googleapis.com",
    "pubsub.googleapis.com",
    "storage.googleapis.com",
    "secretmanager.googleapis.com",
    "iam.googleapis.com",
    "iamcredentials.googleapis.com"
  ])

  project            = var.project_id
  service            = each.value
  disable_on_destroy = false
}

# Create Custom IAM Role
resource "google_project_iam_custom_role" "event_notification_manager" {
  role_id     = var.custom_role_id
  title       = var.custom_role_title
  description = "Allows management of Cloud Storage event notifications and Pub/Sub resources"
  project     = var.project_id
  stage       = "GA"

  permissions = [
    # Storage Permissions
    "storage.buckets.get",
    "storage.buckets.update",

    # Pub/Sub Topic Permissions
    "pubsub.topics.create",
    "pubsub.topics.delete",
    "pubsub.topics.get",
    "pubsub.topics.getIamPolicy",
    "pubsub.topics.list",
    "pubsub.topics.publish",
    "pubsub.topics.setIamPolicy",
    "pubsub.topics.attachSubscription",

    # Pub/Sub Subscription Permissions
    "pubsub.subscriptions.create",
    "pubsub.subscriptions.delete",
    "pubsub.subscriptions.get",
    "pubsub.subscriptions.getIamPolicy",
    "pubsub.subscriptions.list",
    "pubsub.subscriptions.setIamPolicy",
    "pubsub.subscriptions.update",
    "pubsub.subscriptions.consume",
    "pubsub.snapshots.seek",

    # Resource Manager Permissions
    "resourcemanager.projects.get",

    # IAM Permission
    "iam.serviceAccounts.actAs"
  ]

  depends_on = [google_project_service.required_apis]
}

# Create Service Account
resource "google_service_account" "event_subscription_service" {
  account_id   = var.service_account_name
  display_name = "Event Subscription Service Account"
  description  = "Service account for managing Cloud Storage event notifications"
  project      = var.project_id

  depends_on = [google_project_service.required_apis]
}

# Bind Custom Role to Service Account
resource "google_project_iam_member" "service_account_role_binding" {
  project = var.project_id
  role    = google_project_iam_custom_role.event_notification_manager.id
  member  = "serviceAccount:${google_service_account.event_subscription_service.email}"

  depends_on = [
    google_service_account.event_subscription_service,
    google_project_iam_custom_role.event_notification_manager
  ]
}

# Create Service Account Key
resource "google_service_account_key" "event_subscription_key" {
  service_account_id = google_service_account.event_subscription_service.name

  depends_on = [
    google_service_account.event_subscription_service,
    google_project_iam_member.service_account_role_binding
  ]
}

# Store Service Account Key in Secret Manager
resource "google_secret_manager_secret" "service_account_credentials" {
  secret_id = "${var.service_account_name}-credentials"
  project   = var.project_id

  replication {
    auto {}
  }

  labels = {
    purpose    = "gcs-event-subscription"
    managed-by = "terraform"
  }

  depends_on = [google_project_service.required_apis]
}

# Store the actual key content in the secret
resource "google_secret_manager_secret_version" "service_account_credentials_version" {
  secret      = google_secret_manager_secret.service_account_credentials.id
  secret_data = base64decode(google_service_account_key.event_subscription_key.private_key)

  depends_on = [google_secret_manager_secret.service_account_credentials]
}

# Grant the service account access to read its own credentials from Secret Manager
resource "google_secret_manager_secret_iam_member" "service_account_secret_accessor" {
  secret_id = google_secret_manager_secret.service_account_credentials.id
  role      = "roles/secretmanager.secretAccessor"
  member    = "serviceAccount:${google_service_account.event_subscription_service.email}"

  depends_on = [google_secret_manager_secret_version.service_account_credentials_version]
}

# Store credentials in local file (optional - for manual retrieval)
resource "local_file" "credentials" {
  content         = base64decode(google_service_account_key.event_subscription_key.private_key)
  filename        = "${path.module}/gcp-credentials.json"
  file_permission = "0600"
}

# Outputs
output "project_id" {
  description = "GCP Project ID"
  value       = var.project_id
}

output "region" {
  description = "GCP Region"
  value       = var.region
}

output "service_account_email" {
  description = "Email of the created service account"
  value       = google_service_account.event_subscription_service.email
}

output "service_account_id" {
  description = "ID of the created service account"
  value       = google_service_account.event_subscription_service.id
}

output "custom_role_id" {
  description = "ID of the custom IAM role"
  value       = google_project_iam_custom_role.event_notification_manager.id
}

output "custom_role_name" {
  description = "Name of the custom IAM role"
  value       = google_project_iam_custom_role.event_notification_manager.name
}

output "secret_manager_secret_id" {
  description = "Secret Manager secret ID containing service account credentials"
  value       = google_secret_manager_secret.service_account_credentials.secret_id
}

output "secret_manager_secret_name" {
  description = "Full Secret Manager secret name"
  value       = google_secret_manager_secret.service_account_credentials.name
}

output "credentials_file" {
  description = "Path to credentials file"
  value       = "Credentials saved to: ${abspath(local_file.credentials.filename)}"
}

output "retrieve_credentials_command" {
  description = "Command to retrieve service account credentials from Secret Manager"
  value       = "gcloud secrets versions access latest --secret=${google_secret_manager_secret.service_account_credentials.secret_id} --project=${var.project_id}"
}

output "service_account_key_download_note" {
  description = "Note about downloading service account key"
  value       = "Service account key is stored in Secret Manager. Use the retrieve_credentials_command to get the credentials."
}

3.3 Create Variables File

Create a file named terraform.tfvars with your values:

Option A: Default Configuration (Recommended)

project_id           = "your-project-id"
region               = "us-central1"
service_account_name = "event-subscription-service"

Option B: Custom Configuration

project_id           = "your-project-id"
region               = "us-east1"
service_account_name = "prod-event-service"
custom_role_id       = "custom_gcs_event_manager"
custom_role_title    = "Production Event Manager"

Replace your-project-id with your actual GCP project ID.


Step 4: Deploy Infrastructure

4.1 Initialize Terraform

terraform init

Expected output:

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/google versions matching "~> 5.0"...
Terraform has been successfully initialized!

4.2 Preview Changes

terraform plan

This shows what will be created. Review carefully.

You should see:

  • 6 APIs to be enabled

  • 1 custom IAM role to be created

  • 1 service account to be created

  • 1 service account key to be generated

  • 1 IAM role binding to be created

  • 2 Secret Manager resources to be created

  • 1 local file to be created


4.3 Apply Configuration

terraform apply

Type yes when prompted.

Deployment takes 2-3 minutes.


4.4 View Outputs

After successful deployment, you'll see outputs like:

Outputs:

credentials_file = "Credentials saved to: /path/to/gcp-event-notification-setup/gcp-credentials.json"
custom_role_id = "projects/your-project-id/roles/gcs_event_notification_manager"
custom_role_name = "projects/your-project-id/roles/gcs_event_notification_manager"
project_id = "your-project-id"
region = "us-central1"
retrieve_credentials_command = "gcloud secrets versions access latest --secret=event-subscription-service-credentials --project=your-project-id"
service_account_email = "event-subscription-service@your-project-id.iam.gserviceaccount.com"
service_account_id = "projects/your-project-id/serviceAccounts/event-subscription-service@your-project-id.iam.gserviceaccount.com"
service_account_key_download_note = "Service account key is stored in Secret Manager. Use the retrieve_credentials_command to get the credentials."
secret_manager_secret_id = "event-subscription-service-credentials"
secret_manager_secret_name = "projects/123456789/secrets/event-subscription-service-credentials"

Step 5: Retrieve and Use Credentials

5.1 Get Credentials from Local File

The credentials are automatically saved to a local file:

cat gcp-credentials.json

5.2 Get Credentials from Secret Manager

Retrieve from Secret Manager (recommended for production):

gcloud secrets versions access latest \
  --secret=event-subscription-service-credentials \
  --project=your-project-id > retrieved-credentials.json

5.3 Verify Service Account

Check the service account was created:

gcloud iam service-accounts list --project=your-project-id

You should see:

NAME                          EMAIL
Event Subscription Service Account   event-subscription-service@your-project-id.iam.gserviceaccount.com

5.4 Verify Custom Role

Check the custom role:

gcloud iam roles describe gcs_event_notification_manager --project=your-project-id

5.5 Verify Role Binding

Check IAM policy:

gcloud projects get-iam-policy your-project-id \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:event-subscription-service@*"

Step 6: Verify Deployment

6.1 View All Resources Created

terraform state list

Expected output:

google_project_iam_custom_role.event_notification_manager
google_project_iam_member.service_account_role_binding
google_project_service.required_apis["cloudresourcemanager.googleapis.com"]
google_project_service.required_apis["iam.googleapis.com"]
google_project_service.required_apis["iamcredentials.googleapis.com"]
google_project_service.required_apis["pubsub.googleapis.com"]
google_project_service.required_apis["secretmanager.googleapis.com"]
google_project_service.required_apis["storage.googleapis.com"]
google_secret_manager_secret.service_account_credentials
google_secret_manager_secret_iam_member.service_account_secret_accessor
google_secret_manager_secret_version.service_account_credentials_version
google_service_account.event_subscription_service
google_service_account_key.event_subscription_key
local_file.credentials

6.2 Verify Service Account

Check the service account was created:

gcloud iam service-accounts list --project=your-project-id

You should see:

NAME                               EMAIL
Event Subscription Service Account event-subscription-service@your-project-id.iam.gserviceaccount.com

6.3 Verify Custom Role

Check the custom role:

gcloud iam roles describe gcs_event_notification_manager --project=your-project-id

6.4 Verify IAM Policy Binding

Check the role assignment:

gcloud projects get-iam-policy your-project-id \
  --flatten="bindings[].members" \
  --filter="bindings.members:serviceAccount:event-subscription-service@*"

6.5 Verify Enabled APIs

gcloud services list --enabled --project=your-project-id

Step 7: Retrieve Service Account Credentials

7.1 Option 1: From Local File

The credentials are automatically saved to a local file:

cat gcp-credentials.json

7.2 Option 2: From Secret Manager

Retrieve from Secret Manager (recommended for production):

gcloud secrets versions access latest \
  --secret=event-subscription-service-credentials \
  --project=your-project-id > retrieved-credentials.json

7.3 Option 3: From Terraform Output

View the Terraform output that shows where credentials are stored:

terraform output credentials_file
terraform output retrieve_credentials_command

Last Updated: November 2025 Version: 1.0 Author: GCP Event Notification Setup Team

Last updated

Was this helpful?