GCP for DevOps — Google Provider

2 minute read

Google Provider

The Google provider (hashicorp/google) and its beta variant (hashicorp/google-beta) cover nearly every GCP service. This page covers commonly used resources for DevOps workflows.

Provider Configuration

# Use both google and google-beta providers
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 5.0"
    }
    google-beta = {
      source  = "hashicorp/google-beta"
      version = "~> 5.0"
    }
  }
}

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

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

Enable APIs

# Enable required APIs
resource "google_project_service" "apis" {
  for_each = toset([
    "compute.googleapis.com",
    "container.googleapis.com",
    "run.googleapis.com",
    "cloudbuild.googleapis.com",
    "artifactregistry.googleapis.com",
    "secretmanager.googleapis.com",
  ])

  project = var.project_id
  service = each.value

  disable_dependent_services = false
  disable_on_destroy         = false
}

Compute Resources

# VPC Network
resource "google_compute_network" "vpc" {
  name                    = "${var.environment}-vpc"
  auto_create_subnetworks = false
}

# Subnet with secondary ranges for GKE
resource "google_compute_subnetwork" "subnet" {
  name          = "${var.environment}-subnet"
  ip_cidr_range = "10.0.0.0/20"
  region        = var.region
  network       = google_compute_network.vpc.id

  secondary_ip_range {
    range_name    = "pods"
    ip_cidr_range = "10.4.0.0/14"
  }

  secondary_ip_range {
    range_name    = "services"
    ip_cidr_range = "10.8.0.0/20"
  }

  private_ip_google_access = true
}

# Firewall rule
resource "google_compute_firewall" "allow_http" {
  name    = "${var.environment}-allow-http"
  network = google_compute_network.vpc.name

  allow {
    protocol = "tcp"
    ports    = ["80", "443"]
  }

  source_ranges = ["0.0.0.0/0"]
  target_tags   = ["http-server"]
}

GKE Cluster

resource "google_container_cluster" "primary" {
  name     = "${var.environment}-cluster"
  location = var.region

  # Autopilot mode
  enable_autopilot = true

  network    = google_compute_network.vpc.name
  subnetwork = google_compute_subnetwork.subnet.name

  ip_allocation_policy {
    cluster_secondary_range_name  = "pods"
    services_secondary_range_name = "services"
  }

  private_cluster_config {
    enable_private_nodes    = true
    enable_private_endpoint = false
    master_ipv4_cidr_block  = "172.16.0.0/28"
  }

  release_channel {
    channel = "REGULAR"
  }
}

Cloud Run Service

resource "google_cloud_run_v2_service" "api" {
  name     = "${var.environment}-api"
  location = var.region

  template {
    scaling {
      min_instance_count = 1
      max_instance_count = 10
    }

    containers {
      image = "us-central1-docker.pkg.dev/${var.project_id}/my-repo/api:latest"

      ports {
        container_port = 8080
      }

      env {
        name  = "ENV"
        value = var.environment
      }

      env {
        name = "DB_PASSWORD"
        value_source {
          secret_key_ref {
            secret  = google_secret_manager_secret.db_password.secret_id
            version = "latest"
          }
        }
      }

      resources {
        limits = {
          cpu    = "1"
          memory = "512Mi"
        }
      }
    }
  }
}

IAM Resources

# Service account
resource "google_service_account" "app_sa" {
  account_id   = "${var.environment}-app-sa"
  display_name = "Application Service Account"
}

# IAM binding
resource "google_project_iam_member" "app_storage" {
  project = var.project_id
  role    = "roles/storage.objectViewer"
  member  = "serviceAccount:${google_service_account.app_sa.email}"
}

# Workload Identity binding
resource "google_service_account_iam_member" "workload_identity" {
  service_account_id = google_service_account.app_sa.name
  role               = "roles/iam.workloadIdentityUser"
  member             = "serviceAccount:${var.project_id}.svc.id.goog[default/app-ksa]"
}

Secret Manager

resource "google_secret_manager_secret" "db_password" {
  secret_id = "${var.environment}-db-password"

  replication {
    auto {}
  }
}

resource "google_secret_manager_secret_version" "db_password_v1" {
  secret      = google_secret_manager_secret.db_password.id
  secret_data = var.db_password
}

Cloud Storage

resource "google_storage_bucket" "artifacts" {
  name          = "${var.project_id}-${var.environment}-artifacts"
  location      = var.region
  force_destroy = var.environment != "prod"

  versioning {
    enabled = true
  }

  lifecycle_rule {
    condition {
      age = 30
    }
    action {
      type = "Delete"
    }
  }

  uniform_bucket_level_access = true
}

Artifact Registry

resource "google_artifact_registry_repository" "docker" {
  location      = var.region
  repository_id = "${var.environment}-docker"
  format        = "DOCKER"
  description   = "Docker images for ${var.environment}"
}

Common Mistakes

Mistake Why It’s Wrong Fix
Not enabling APIs first Resource creation fails Use google_project_service
Using google for beta features Feature not available Use google-beta provider
Hardcoding names Collision across environments Prefix with var.environment
force_destroy = true on prod buckets Data loss risk Conditionally set per environment
Forgetting secondary IP ranges for GKE Pod/service networking fails Always configure secondary ranges

Quick Reference

Resource Terraform Type
VPC google_compute_network
Subnet google_compute_subnetwork
VM google_compute_instance
GKE google_container_cluster
Cloud Run google_cloud_run_v2_service
Service Account google_service_account
Secret google_secret_manager_secret
Bucket google_storage_bucket

Next → Terraform State in GCS

Updated: