Terraform as a Service with Google Cloud's Infrastructure Manager


GCP (Google Cloud Platform) Infrastructure Manager is a fully managed infrastructure-as-code (IaC) service that allows us to provision, manage, and orchestrate Google Cloud resources using Terraform. It provides a managed way to use Terraform with GCP, eliminating the need for us to manage the state ourselves. Think of it as Terraform-as-a-Service living directly within our GCP project. Instead of running terraform apply
on our environment and worrying about where to store the state file, we hand our Terraform code to Infrastructure Manager, and it handles the rest.
GCP Infrastructure Manager doesn't have direct charges. Instead, it charges for Cloud Build execution and Cloud Storage. Cloud Build includes 2,500 free build-minutes each month before charging begins and Cloud Storage has a free tier with 5 GB of standard storage per month.
Let's create a practical example that deploys a free-tier VM with NGINX exposed to the internet, executed locally using Infrastructure Manager.
Pre-requisites
Google Cloud CLI installed and authenticated.
APIs
We need to enable the Infrastructure Manager API, the Compute Engine API, and the Cloud Storage API:
gcloud services enable config.googleapis.com
gcloud services enable compute.googleapis.com
gcloud services enable storage.googleapis.com
Terraform
Create a terraform/main.tf
file with the following content:
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = ">= 4.34.0"
}
}
}
resource "google_compute_instance" "free_tier_vm" {
project = var.project_id
machine_type = "e2-micro"
zone = "us-central1-a"
name = "my-first-vm"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = "default"
access_config {}
}
tags = ["http-server"]
metadata = {
startup-script = file("${path.module}/startup-script.sh")
}
}
resource "google_compute_firewall" "allow_http" {
project = var.project_id
name = "allow-http-ingress"
network = "default"
allow {
protocol = "tcp"
ports = ["80"]
}
target_tags = ["http-server"]
source_ranges = ["0.0.0.0/0"]
}
variable "project_id" {
type = string
description = "The GCP project ID to deploy resources into."
}
output "vm_external_ip" {
description = "The external IP address of the web server VM."
value = google_compute_instance.free_tier_vm.network_interface[0].access_config[0].nat_ip
}
This Terraform script creates a basic web server using free-tier resources. Here's what it does:
google_compute_instance
: Creates ane2-micro
VM instance (free-tier eligible) deployed inus-central1-a
(free-tier region) . Theboot_disk
block defines the main disk that contains the operating system (specified by theimage
property) used to start the VM instance. Thenetwork_interface
block automatically assigns an internal (private) IP address in thedefault
VPC network. Theaccess_config
block instructs GCP to assign an external (public) IP address. By default, this IP address is ephemeral (changes when VM restarts). Thetags
property is used by the firewall rule to identify the VM instance. Thestartup_script
property defines a script that runs automatically when the VM starts up for the first time.google_compute_firewall
: Creates a rule namedallow-http-ingress
that opensTCP
port80
(HTTP) for incoming traffic, allowing access from anywhere on the internet (0.0.0.0/0
). This rule applies only to instances tagged withhttp-server
.
Create the terraform/startup-script.sh
with the following content:
#!/bin/bash
set -e
echo "=== Startup script started at $(date) ==="
apt-get update -y
apt-get install -y nginx
systemctl start nginx
systemctl enable nginx
echo "=== Startup script completed at $(date) ==="
Windows line endings could produce errors. Ensure the file uses Unix line endings (
LF
, notCRLF
).
Deploy
Infrastructure Manager requires a service account with specific IAM roles:
gcloud iam service-accounts create infra-manager-sa --display-name=infra-manager-sa --project=<MY_PROJECT_ID>
gcloud projects add-iam-policy-binding <MY_PROJECT_ID> --member="serviceAccount:infra-manager-sa@<MY_PROJECT_ID>.iam.gserviceaccount.com" --role="roles/admin"
Now, we can use the following command to deploy our VM:
gcloud infra-manager deployments apply my-first-deployment --location=us-central1 --local-source=./terraform --input-values=project_id=<MY_PROJECT_ID> --service-account=projects/<MY_PROJECT_ID>/serviceAccounts/infra-manager-sa@<MY_PROJECT_ID>.iam.gserviceaccount.com
After the command finishes, we can check the public IP of the VM with the following command:
gcloud compute instances describe my-first-vm --zone=us-central1-a --format="value(networkInterfaces[0].accessConfigs[0].natIP)"
Clean Up
To avoid any charges and clean up resources, run:
gcloud infra-manager deployments delete my-deployment --location=us-central1
The official documentation offers more details about the commands used.
You can find all the code here. Thanks, and happy coding.
Subscribe to my newsletter
Read articles from Raul Naupari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Raul Naupari
Raul Naupari
Somebody who likes to code