Provisioning a GCP VPC with Pulumi

Learn how to build a custom-mode VPC with public and private subnets and firewall rules using Pulumi and TypeScript

Provisioning a GCP VPC with Pulumi

This guide builds the same VPC topology as the Terraform VPC guide on this site, using Pulumi and @pulumi/gcp - a custom-mode network with public and private subnets and the firewall rules the rest of this GCP Pulumi series builds on.

Prerequisites

npm install @pulumi/pulumi @pulumi/gcp
  • Pulumi CLI and gcloud auth application-default login completed
  • pulumi config set gcp:project <your-project-id>

Custom-Mode Network and Subnets

GCP networks are either “auto” mode (a subnet is created automatically in every region) or “custom” mode (you define exactly which subnets exist, where) - autoCreateSubnetworks: false is what selects custom mode, the same choice the Terraform VPC guide makes and the one production setups almost always want, since auto mode creates a subnet in every GCP region whether you use it or not:

// index.ts
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const config = new pulumi.Config();
const region = config.get("region") ?? "us-central1";

const network = new gcp.compute.Network("main", {
    name: "app-vpc",
    autoCreateSubnetworks: false,
});

const publicSubnet = new gcp.compute.Subnetwork("public", {
    name: "public-subnet",
    network: network.id,
    ipCidrRange: "10.0.1.0/24",
    region: region,
});

const privateSubnet = new gcp.compute.Subnetwork("private", {
    name: "private-subnet",
    network: network.id,
    ipCidrRange: "10.0.2.0/24",
    region: region,
    privateIpGoogleAccess: true,
});

privateIpGoogleAccess: true on the private subnet lets instances with no external IP still reach Google APIs (Cloud Storage, Cloud Functions, and so on) over Google’s internal network - without it, an instance with no public IP has no route to any Google service either.

Firewall Rules

Unlike AWS/Azure security groups, which are attached to specific resources, GCP firewall rules apply network-wide and use targetTags/sourceRanges to scope which instances and traffic they affect - closer in spirit to a shared, tag-matched policy than a per-resource attachment:

const allowHttps = new gcp.compute.Firewall("allow-https", {
    name: "allow-https",
    network: network.id,
    allows: [{
        protocol: "tcp",
        ports: ["443"],
    }],
    sourceRanges: ["0.0.0.0/0"],
    targetTags: ["https-server"],
});

const allowInternal = new gcp.compute.Firewall("allow-internal", {
    name: "allow-internal",
    network: network.id,
    allows: [{
        protocol: "tcp",
        ports: ["0-65535"],
    }],
    sourceRanges: ["10.0.0.0/16"],
});

allowHttps only applies to instances tagged https-server (see the Compute Engine guide) even though its sourceRanges is open to the internet - the tag match is what narrows it, not the source range. allowInternal has no targetTags, so it applies to every instance on the network, letting anything inside the VPC’s own CIDR talk to anything else on any port.

Stack Outputs

export const networkId = network.id;
export const publicSubnetId = publicSubnet.id;
export const privateSubnetId = privateSubnet.id;

Best Practices

  1. Always use custom-mode networks (autoCreateSubnetworks: false) for anything beyond a throwaway experiment - auto mode’s one-subnet-per-region default is almost never the topology you actually want.
  2. Scope firewall rules with targetTags, not just sourceRanges - a rule with no target tag applies to every instance on the network, which is rarely the intent.
  3. Enable privateIpGoogleAccess on any subnet holding instances without public IPs that still need to call Google APIs (Cloud Storage, Pub/Sub, Cloud Functions) - it’s easy to forget and the failure mode (API calls timing out) doesn’t obviously point back to this setting.

Conclusion

This VPC is the foundation the rest of this GCP Pulumi series builds on - the Compute Engine and GKE guides both reference network, publicSubnet, and privateSubnet from here.

For more Pulumi topics, check out: