Terraform GCP Setup
Complete guide to setting up Terraform with Google Cloud Platform (GCP). Learn how to configure authentication, create your first GCP resources, and manage infrastructure.
Prerequisites
- ✅ GCP Account
- ✅ gcloud CLI installed and configured
- ✅ Terraform installed
- ✅ GCP Project created
- ✅ Service Account with appropriate permissions
Installation
Install gcloud CLI
# macOS
brew install --cask google-cloud-sdk
# Linux
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
# Windows
# Download from: https://cloud.google.com/sdk/docs/install
Initialize gcloud
gcloud init
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
Authentication
Method 1: Application Default Credentials (ADC)
# Authenticate with ADC
gcloud auth application-default login
# Terraform will automatically use ADC
provider "google" {
project = var.project_id
region = var.region
}
Method 2: Service Account Key
# Create service account
gcloud iam service-accounts create terraform \
--display-name="Terraform Service Account"
# Grant permissions
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID \
--member="serviceAccount:terraform@YOUR_PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/owner"
# Create key
gcloud iam service-accounts keys create credentials.json \
--iam-account=terraform@YOUR_PROJECT_ID.iam.gserviceaccount.com
# Use in Terraform
provider "google" {
project = var.project_id
region = var.region
credentials = file("credentials.json")
}
Method 3: Environment Variable
export GOOGLE_APPLICATION_CREDENTIALS="path/to/credentials.json"
# Or export service account key content
export GOOGLE_CREDENTIALS='{"type":"service_account",...}'
# In Terraform
provider "google" {
project = var.project_id
region = var.region
}
Basic GCP Provider Configuration
versions.tf
terraform {
required_version = ">= 1.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider.tf
provider "google" {
project = var.project_id
region = var.region
zone = var.zone
}
IAM Permissions
Required Roles
# Grant necessary roles to service account
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/compute.admin"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountAdmin"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:terraform@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/storage.admin"
💡 Best Practice: Use minimum required permissions.
Grant only the roles needed for your infrastructure.
Complete Example: VPC with Compute Engine
variables.tf
variable "project_id" {
description = "GCP Project ID"
type = string
}
variable "region" {
description = "GCP region"
type = string
default = "us-central1"
}
variable "zone" {
description = "GCP zone"
type = string
default = "us-central1-a"
}
variable "environment" {
description = "Environment name"
type = string
}
variable "instance_type" {
description = "GCE instance type"
type = string
default = "e2-micro"
}
main.tf
# VPC Network
resource "google_compute_network" "vpc" {
name = "${var.environment}-vpc"
auto_create_subnetworks = false
project = var.project_id
}
# Public Subnet
resource "google_compute_subnetwork" "public" {
name = "${var.environment}-public-subnet"
ip_cidr_range = "10.0.1.0/24"
region = var.region
network = google_compute_network.vpc.id
project = var.project_id
}
# Firewall Rule - Allow HTTP
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"]
project = var.project_id
}
# Firewall Rule - Allow SSH
resource "google_compute_firewall" "allow_ssh" {
name = "${var.environment}-allow-ssh"
network = google_compute_network.vpc.name
allow {
protocol = "tcp"
ports = ["22"]
}
source_ranges = ["0.0.0.0/0"]
target_tags = ["ssh-server"]
project = var.project_id
}
# Compute Engine Instance
resource "google_compute_instance" "web" {
name = "${var.environment}-web-server"
machine_type = var.instance_type
zone = var.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
size = 10
}
}
network_interface {
network = google_compute_network.vpc.name
subnetwork = google_compute_subnetwork.public.name
access_config {
// Ephemeral public IP
}
}
metadata_startup_script = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y nginx
systemctl start nginx
systemctl enable nginx
echo "<h1>Hello from Terraform on GCP!</h1>" > /var/www/html/index.html
EOF
tags = ["http-server", "ssh-server"]
project = var.project_id
}
outputs.tf
output "vpc_id" {
description = "ID of the VPC network"
value = google_compute_network.vpc.id
}
output "instance_id" {
description = "ID of the compute instance"
value = google_compute_instance.web.id
}
output "instance_public_ip" {
description = "Public IP of the compute instance"
value = google_compute_instance.web.network_interface[0].access_config[0].nat_ip
}
output "instance_name" {
description = "Name of the compute instance"
value = google_compute_instance.web.name
}
terraform.tfvars
project_id = "my-gcp-project-id"
region = "us-central1"
zone = "us-central1-a"
environment = "production"
instance_type = "e2-micro"
Remote State with GCS
GCS Backend Configuration
terraform {
backend "gcs" {
bucket = "terraform-state-bucket"
prefix = "terraform/state"
project = "my-gcp-project"
}
}
Create GCS Bucket for State
# Create GCS bucket
gsutil mb -p PROJECT_ID -l us-central1 gs://terraform-state-bucket
# Enable versioning
gsutil versioning set on gs://terraform-state-bucket
# Enable encryption
gsutil encryption set -k projects/PROJECT_ID/locations/global/keyRings/KEY_RING/cryptoKeys/KEY_NAME \
gs://terraform-state-bucket
Common GCP Resources
Cloud Storage Bucket
resource "google_storage_bucket" "website" {
name = "${var.environment}-website-bucket"
location = var.region
force_destroy = false
versioning {
enabled = true
}
uniform_bucket_level_access {
enabled = true
}
project = var.project_id
}
Cloud SQL Database
resource "google_sql_database_instance" "main" {
name = "${var.environment}-db"
database_version = "POSTGRES_15"
region = var.region
settings {
tier = "db-f1-micro"
backup_configuration {
enabled = true
start_time = "03:00"
}
ip_configuration {
ipv4_enabled = true
authorized_networks {
value = "0.0.0.0/0"
}
}
}
project = var.project_id
}
resource "google_sql_database" "main" {
name = "mydb"
instance = google_sql_database_instance.main.name
project = var.project_id
}
resource "google_sql_user" "main" {
name = "admin"
instance = google_sql_database_instance.main.name
password = var.db_password
project = var.project_id
}
Load Balancer
resource "google_compute_backend_service" "web" {
name = "${var.environment}-backend-service"
protocol = "HTTP"
port_name = "http"
timeout_sec = 10
backend {
group = google_compute_instance_group.web.id
}
health_checks = [google_compute_health_check.web.id]
project = var.project_id
}
resource "google_compute_health_check" "web" {
name = "${var.environment}-health-check"
http_health_check {
port = 80
path = "/"
}
project = var.project_id
}
resource "google_compute_url_map" "web" {
name = "${var.environment}-url-map"
default_service = google_compute_backend_service.web.id
project = var.project_id
}
resource "google_compute_target_http_proxy" "web" {
name = "${var.environment}-http-proxy"
url_map = google_compute_url_map.web.id
project = var.project_id
}
resource "google_compute_global_forwarding_rule" "web" {
name = "${var.environment}-forwarding-rule"
target = google_compute_target_http_proxy.web.id
port_range = "80"
project = var.project_id
}
Deployment Steps
1. Initialize Terraform
terraform init
2. Validate Configuration
terraform validate
3. Format Files
terraform fmt
4. Plan Changes
terraform plan
5. Apply Changes
terraform apply
Troubleshooting
Common Issues
⚠️ Issue: Authentication Error
Error: Error: google: could not find default credentials
Solution: Run gcloud auth application-default login or set credentials.
⚠️ Issue: Permission Denied
Error: Error: Error 403: Permission denied
Solution: Ensure service account has required IAM roles.
💡 Tip: Enable required APIs for your project:
gcloud services enable compute.googleapis.com
gcloud services enable sqladmin.googleapis.com
gcloud services enable storage-api.googleapis.com
Next Steps
- Modules - Create reusable modules
- Best Practices - Production-ready practices
- State Management - Manage Terraform state