GCP for DevOps — Google Provider
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