GCP Provider Setup
Why GCP with Pulumi?
The Problem: Google Cloud's Deployment Manager uses YAML/Jinja templates that lack type safety and are difficult to test or refactor.
The Solution: Pulumi provides first-class GCP support with strongly typed resources for Google Cloud services, giving you broad coverage and type safety.
Real Impact: Pulumi's GCP provider (@pulumi/gcp) is updated continuously as Google Cloud ships new services and features, keeping your IaC up to date.
Real-World Analogy
Think of GCP with Pulumi as a smart factory automation system:
- Projects = Factory buildings that isolate different product lines
- VPC Networks = Internal conveyor belt systems connecting machines
- Compute Engine = Heavy-duty machines on the factory floor
- Cloud Functions = Automated sensors that trigger actions on demand
- Cloud Storage = Warehouses that store raw materials and finished goods
Key GCP Concepts in Pulumi
Project-Based Organization
GCP organizes resources into projects. Configure the project and region in Pulumi config for consistent deployments.
GCP Provider
Use the @pulumi/gcp provider for broad resource coverage with accurate types. The older Google Native provider is deprecated.
Service Account Auth
Use service accounts with JSON key files or workload identity for secure authentication in CI/CD pipelines.
Labels Strategy
Apply consistent labels across all GCP resources for cost allocation, environment tracking, and team ownership.
Installing the GCP Provider
# Create a new Pulumi GCP project
pulumi new gcp-typescript
# Install the GCP provider
npm install @pulumi/gcp
# Configure project and region
pulumi config set gcp:project my-gcp-project-id
pulumi config set gcp:region us-central1
# Authenticate with gcloud CLI
gcloud auth application-default login
VPC & Networking
Creating VPC and Subnets
import * as gcp from "@pulumi/gcp";
// Create a custom VPC network
const network = new gcp.compute.Network("app-network", {
autoCreateSubnetworks: false,
description: "Main application VPC",
});
// Create subnets in different regions
const subnetCentral = new gcp.compute.Subnetwork("central-subnet", {
network: network.id,
ipCidrRange: "10.0.1.0/24",
region: "us-central1",
privateIpGoogleAccess: true,
});
const subnetEast = new gcp.compute.Subnetwork("east-subnet", {
network: network.id,
ipCidrRange: "10.0.2.0/24",
region: "us-east1",
});
// Firewall rule for HTTP traffic
const httpFirewall = new gcp.compute.Firewall("allow-http", {
network: network.id,
allows: [{ protocol: "tcp", ports: ["80", "443"] }],
sourceRanges: ["0.0.0.0/0"],
targetTags: ["web-server"],
});
// Cloud Router for NAT
const router = new gcp.compute.Router("nat-router", {
network: network.id,
region: "us-central1",
});
const nat = new gcp.compute.RouterNat("cloud-nat", {
router: router.name,
region: "us-central1",
natIpAllocateOption: "AUTO_ONLY",
sourceSubnetworkIpRangesToNat: "ALL_SUBNETWORKS_ALL_IP_RANGES",
});
Compute (GCE & Cloud Functions)
Compute Engine Instance
// Create a Compute Engine instance
const instance = new gcp.compute.Instance("web-server", {
machineType: "e2-medium",
zone: "us-central1-a",
bootDisk: {
initializeParams: {
image: "debian-cloud/debian-11",
size: 20,
},
},
networkInterfaces: [{
network: network.id,
subnetwork: subnetCentral.id,
accessConfigs: [{}], // Gives external IP
}],
metadataStartupScript: `#!/bin/bash
apt-get update
apt-get install -y nginx
echo "Hello from Pulumi on GCP!" > /var/www/html/index.html
systemctl start nginx`,
tags: ["web-server"],
labels: { environment: pulumi.getStack() },
});
export const instanceIp = instance.networkInterfaces[0].accessConfigs[0].natIp;
Cloud Functions
// Cloud Storage bucket for function source
const sourceBucket = new gcp.storage.Bucket("func-source", {
location: "US",
uniformBucketLevelAccess: true,
});
// Upload function source code
const sourceArchive = new gcp.storage.BucketObject("func-zip", {
bucket: sourceBucket.name,
source: new pulumi.asset.FileArchive("./function-source"),
});
// Create the Cloud Function (2nd gen, HTTP-triggered by default)
const func = new gcp.cloudfunctionsv2.Function("api-function", {
location: "us-central1",
buildConfig: {
runtime: "nodejs22",
entryPoint: "handler",
source: {
storageSource: {
bucket: sourceBucket.name,
object: sourceArchive.name,
},
},
},
serviceConfig: {
availableMemory: "256M",
environmentVariables: {
STAGE: pulumi.getStack(),
},
},
});
// Allow public invocation (2nd gen functions run on Cloud Run)
const invoker = new gcp.cloudrunv2.ServiceIamMember("invoker", {
name: func.name,
location: func.location,
role: "roles/run.invoker",
member: "allUsers",
});
export const functionUrl = func.url;
Storage (GCS & Firestore)
Cloud Storage and Firestore
// Cloud Storage bucket with lifecycle rules
const dataBucket = new gcp.storage.Bucket("data-bucket", {
location: "US",
storageClass: "STANDARD",
uniformBucketLevelAccess: true,
versioning: { enabled: true },
lifecycleRules: [{
action: { type: "SetStorageClass", storageClass: "NEARLINE" },
condition: { age: 30 },
}, {
action: { type: "Delete" },
condition: { age: 365 },
}],
labels: { environment: pulumi.getStack() },
});
// Firestore database (Native mode)
const firestore = new gcp.firestore.Database("app-db", {
locationId: "nam5",
type: "FIRESTORE_NATIVE",
});
export const bucketUrl = dataBucket.url;
IAM & Service Accounts
Service Accounts and IAM Bindings
// Create a service account for the application
const appSa = new gcp.serviceaccount.Account("app-sa", {
accountId: "app-service-account",
displayName: "Application Service Account",
});
// Grant Storage Object Viewer role
new gcp.storage.BucketIAMMember("bucket-viewer", {
bucket: dataBucket.name,
role: "roles/storage.objectViewer",
member: appSa.email.apply(e => `serviceAccount:${e}`),
});
// Grant Firestore User role at project level
new gcp.projects.IAMMember("firestore-user", {
project: appSa.project,
role: "roles/datastore.user",
member: appSa.email.apply(e => `serviceAccount:${e}`),
});
export const serviceAccountEmail = appSa.email;
Quick Reference
GCP Resource Cheat Sheet
| Resource | Pulumi Class | Key Properties |
|---|---|---|
| VPC Network | gcp.compute.Network |
autoCreateSubnetworks, description |
| Subnet | gcp.compute.Subnetwork |
ipCidrRange, region, network |
| GCE Instance | gcp.compute.Instance |
machineType, zone, bootDisk |
| Cloud Function | gcp.cloudfunctionsv2.Function |
location, buildConfig, serviceConfig |
| Cloud Storage | gcp.storage.Bucket |
location, storageClass, versioning |
| Firestore | gcp.firestore.Database |
locationId, type |
| Service Account | gcp.serviceaccount.Account |
accountId, displayName |
GCP Authentication Methods
Authentication Options
gcloud auth application-default login- Interactive login for development- Service Account Key - Set GOOGLE_CREDENTIALS env var with JSON key file path
- Workload Identity - Federate with GitHub Actions or other OIDC providers
- GCE Metadata - Automatic when running on Compute Engine or GKE