Configure GCP Network Services Gateways

The gcp:networkservices/gateway:Gateway resource, part of the Pulumi GCP provider, defines Network Services gateways that route traffic through proxies or load balancers. This guide focuses on three capabilities: open mesh gateways for service routing, secure web gateways with TLS termination, and security policy integration.

Gateway types determine infrastructure requirements. Open mesh gateways route service traffic without VPC dependencies. Secure web gateways require VPC networks, subnets (including proxy-only subnets), Certificate Manager certificates, and GatewaySecurityPolicy resources. The examples are intentionally small. Combine them with your own networking and security infrastructure.

Create an open mesh gateway for service routing

Service mesh deployments route traffic across services without VPC-specific configuration, using gateways that listen on all interfaces.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.networkservices.Gateway("default", {
    name: "my-gateway",
    scope: "default-scope-basic",
    type: "OPEN_MESH",
    ports: [443],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networkservices.Gateway("default",
    name="my-gateway",
    scope="default-scope-basic",
    type="OPEN_MESH",
    ports=[443])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networkservices.NewGateway(ctx, "default", &networkservices.GatewayArgs{
			Name:  pulumi.String("my-gateway"),
			Scope: pulumi.String("default-scope-basic"),
			Type:  pulumi.String("OPEN_MESH"),
			Ports: pulumi.IntArray{
				pulumi.Int(443),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.NetworkServices.Gateway("default", new()
    {
        Name = "my-gateway",
        Scope = "default-scope-basic",
        Type = "OPEN_MESH",
        Ports = new[]
        {
            443,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.Gateway;
import com.pulumi.gcp.networkservices.GatewayArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Gateway("default", GatewayArgs.builder()
            .name("my-gateway")
            .scope("default-scope-basic")
            .type("OPEN_MESH")
            .ports(443)
            .build());

    }
}
resources:
  default:
    type: gcp:networkservices:Gateway
    properties:
      name: my-gateway
      scope: default-scope-basic
      type: OPEN_MESH
      ports:
        - 443

The type property set to OPEN_MESH creates a gateway that listens on 0.0.0.0 for IPv4 and :: for IPv6. The scope property determines how configurations merge: multiple gateway instances with the same scope present as a single configuration to the proxy. The ports array specifies which ports receive traffic.

Add labels and description for organization

Teams managing multiple gateways tag them with metadata for cost tracking and environment identification.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.networkservices.Gateway("default", {
    name: "my-gateway",
    labels: {
        foo: "bar",
    },
    description: "my description",
    type: "OPEN_MESH",
    ports: [443],
    scope: "default-scope-advance",
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networkservices.Gateway("default",
    name="my-gateway",
    labels={
        "foo": "bar",
    },
    description="my description",
    type="OPEN_MESH",
    ports=[443],
    scope="default-scope-advance")
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networkservices.NewGateway(ctx, "default", &networkservices.GatewayArgs{
			Name: pulumi.String("my-gateway"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Type:        pulumi.String("OPEN_MESH"),
			Ports: pulumi.IntArray{
				pulumi.Int(443),
			},
			Scope: pulumi.String("default-scope-advance"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.NetworkServices.Gateway("default", new()
    {
        Name = "my-gateway",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Type = "OPEN_MESH",
        Ports = new[]
        {
            443,
        },
        Scope = "default-scope-advance",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.Gateway;
import com.pulumi.gcp.networkservices.GatewayArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Gateway("default", GatewayArgs.builder()
            .name("my-gateway")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .type("OPEN_MESH")
            .ports(443)
            .scope("default-scope-advance")
            .build());

    }
}
resources:
  default:
    type: gcp:networkservices:Gateway
    properties:
      name: my-gateway
      labels:
        foo: bar
      description: my description
      type: OPEN_MESH
      ports:
        - 443
      scope: default-scope-advance

The labels property adds key-value pairs for organization and cost allocation. The description property provides human-readable context. These properties work with any gateway type.

Deploy a secure web gateway with TLS and security policies

Organizations filtering outbound traffic use secure web gateways that terminate TLS and apply security policies.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";

const _default = new gcp.certificatemanager.Certificate("default", {
    name: "my-certificate",
    location: "us-central1",
    selfManaged: {
        pemCertificate: std.file({
            input: "test-fixtures/cert.pem",
        }).then(invoke => invoke.result),
        pemPrivateKey: std.file({
            input: "test-fixtures/private-key.pem",
        }).then(invoke => invoke.result),
    },
});
const defaultNetwork = new gcp.compute.Network("default", {
    name: "my-network",
    routingMode: "REGIONAL",
    autoCreateSubnetworks: false,
});
const defaultSubnetwork = new gcp.compute.Subnetwork("default", {
    name: "my-subnetwork-name",
    purpose: "PRIVATE",
    ipCidrRange: "10.128.0.0/20",
    region: "us-central1",
    network: defaultNetwork.id,
    role: "ACTIVE",
});
const proxyonlysubnet = new gcp.compute.Subnetwork("proxyonlysubnet", {
    name: "my-proxy-only-subnetwork",
    purpose: "REGIONAL_MANAGED_PROXY",
    ipCidrRange: "192.168.0.0/23",
    region: "us-central1",
    network: defaultNetwork.id,
    role: "ACTIVE",
});
const defaultGatewaySecurityPolicy = new gcp.networksecurity.GatewaySecurityPolicy("default", {
    name: "my-policy-name",
    location: "us-central1",
});
const defaultGatewaySecurityPolicyRule = new gcp.networksecurity.GatewaySecurityPolicyRule("default", {
    name: "my-policyrule-name",
    location: "us-central1",
    gatewaySecurityPolicy: defaultGatewaySecurityPolicy.name,
    enabled: true,
    priority: 1,
    sessionMatcher: "host() == 'example.com'",
    basicProfile: "ALLOW",
});
const defaultGateway = new gcp.networkservices.Gateway("default", {
    name: "my-gateway1",
    location: "us-central1",
    addresses: ["10.128.0.99"],
    type: "SECURE_WEB_GATEWAY",
    ports: [443],
    scope: "my-default-scope1",
    certificateUrls: [_default.id],
    gatewaySecurityPolicy: defaultGatewaySecurityPolicy.id,
    network: defaultNetwork.id,
    subnetwork: defaultSubnetwork.id,
    deleteSwgAutogenRouterOnDestroy: true,
}, {
    dependsOn: [proxyonlysubnet],
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

default = gcp.certificatemanager.Certificate("default",
    name="my-certificate",
    location="us-central1",
    self_managed={
        "pem_certificate": std.file(input="test-fixtures/cert.pem").result,
        "pem_private_key": std.file(input="test-fixtures/private-key.pem").result,
    })
default_network = gcp.compute.Network("default",
    name="my-network",
    routing_mode="REGIONAL",
    auto_create_subnetworks=False)
default_subnetwork = gcp.compute.Subnetwork("default",
    name="my-subnetwork-name",
    purpose="PRIVATE",
    ip_cidr_range="10.128.0.0/20",
    region="us-central1",
    network=default_network.id,
    role="ACTIVE")
proxyonlysubnet = gcp.compute.Subnetwork("proxyonlysubnet",
    name="my-proxy-only-subnetwork",
    purpose="REGIONAL_MANAGED_PROXY",
    ip_cidr_range="192.168.0.0/23",
    region="us-central1",
    network=default_network.id,
    role="ACTIVE")
default_gateway_security_policy = gcp.networksecurity.GatewaySecurityPolicy("default",
    name="my-policy-name",
    location="us-central1")
default_gateway_security_policy_rule = gcp.networksecurity.GatewaySecurityPolicyRule("default",
    name="my-policyrule-name",
    location="us-central1",
    gateway_security_policy=default_gateway_security_policy.name,
    enabled=True,
    priority=1,
    session_matcher="host() == 'example.com'",
    basic_profile="ALLOW")
default_gateway = gcp.networkservices.Gateway("default",
    name="my-gateway1",
    location="us-central1",
    addresses=["10.128.0.99"],
    type="SECURE_WEB_GATEWAY",
    ports=[443],
    scope="my-default-scope1",
    certificate_urls=[default.id],
    gateway_security_policy=default_gateway_security_policy.id,
    network=default_network.id,
    subnetwork=default_subnetwork.id,
    delete_swg_autogen_router_on_destroy=True,
    opts = pulumi.ResourceOptions(depends_on=[proxyonlysubnet]))
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/certificatemanager"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networksecurity"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		invokeFile, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/cert.pem",
		}, nil)
		if err != nil {
			return err
		}
		invokeFile1, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/private-key.pem",
		}, nil)
		if err != nil {
			return err
		}
		_default, err := certificatemanager.NewCertificate(ctx, "default", &certificatemanager.CertificateArgs{
			Name:     pulumi.String("my-certificate"),
			Location: pulumi.String("us-central1"),
			SelfManaged: &certificatemanager.CertificateSelfManagedArgs{
				PemCertificate: pulumi.String(invokeFile.Result),
				PemPrivateKey:  pulumi.String(invokeFile1.Result),
			},
		})
		if err != nil {
			return err
		}
		defaultNetwork, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
			Name:                  pulumi.String("my-network"),
			RoutingMode:           pulumi.String("REGIONAL"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		defaultSubnetwork, err := compute.NewSubnetwork(ctx, "default", &compute.SubnetworkArgs{
			Name:        pulumi.String("my-subnetwork-name"),
			Purpose:     pulumi.String("PRIVATE"),
			IpCidrRange: pulumi.String("10.128.0.0/20"),
			Region:      pulumi.String("us-central1"),
			Network:     defaultNetwork.ID(),
			Role:        pulumi.String("ACTIVE"),
		})
		if err != nil {
			return err
		}
		proxyonlysubnet, err := compute.NewSubnetwork(ctx, "proxyonlysubnet", &compute.SubnetworkArgs{
			Name:        pulumi.String("my-proxy-only-subnetwork"),
			Purpose:     pulumi.String("REGIONAL_MANAGED_PROXY"),
			IpCidrRange: pulumi.String("192.168.0.0/23"),
			Region:      pulumi.String("us-central1"),
			Network:     defaultNetwork.ID(),
			Role:        pulumi.String("ACTIVE"),
		})
		if err != nil {
			return err
		}
		defaultGatewaySecurityPolicy, err := networksecurity.NewGatewaySecurityPolicy(ctx, "default", &networksecurity.GatewaySecurityPolicyArgs{
			Name:     pulumi.String("my-policy-name"),
			Location: pulumi.String("us-central1"),
		})
		if err != nil {
			return err
		}
		_, err = networksecurity.NewGatewaySecurityPolicyRule(ctx, "default", &networksecurity.GatewaySecurityPolicyRuleArgs{
			Name:                  pulumi.String("my-policyrule-name"),
			Location:              pulumi.String("us-central1"),
			GatewaySecurityPolicy: defaultGatewaySecurityPolicy.Name,
			Enabled:               pulumi.Bool(true),
			Priority:              pulumi.Int(1),
			SessionMatcher:        pulumi.String("host() == 'example.com'"),
			BasicProfile:          pulumi.String("ALLOW"),
		})
		if err != nil {
			return err
		}
		_, err = networkservices.NewGateway(ctx, "default", &networkservices.GatewayArgs{
			Name:     pulumi.String("my-gateway1"),
			Location: pulumi.String("us-central1"),
			Addresses: pulumi.StringArray{
				pulumi.String("10.128.0.99"),
			},
			Type: pulumi.String("SECURE_WEB_GATEWAY"),
			Ports: pulumi.IntArray{
				pulumi.Int(443),
			},
			Scope: pulumi.String("my-default-scope1"),
			CertificateUrls: pulumi.StringArray{
				_default.ID(),
			},
			GatewaySecurityPolicy:           defaultGatewaySecurityPolicy.ID(),
			Network:                         defaultNetwork.ID(),
			Subnetwork:                      defaultSubnetwork.ID(),
			DeleteSwgAutogenRouterOnDestroy: pulumi.Bool(true),
		}, pulumi.DependsOn([]pulumi.Resource{
			proxyonlysubnet,
		}))
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var @default = new Gcp.CertificateManager.Certificate("default", new()
    {
        Name = "my-certificate",
        Location = "us-central1",
        SelfManaged = new Gcp.CertificateManager.Inputs.CertificateSelfManagedArgs
        {
            PemCertificate = Std.File.Invoke(new()
            {
                Input = "test-fixtures/cert.pem",
            }).Apply(invoke => invoke.Result),
            PemPrivateKey = Std.File.Invoke(new()
            {
                Input = "test-fixtures/private-key.pem",
            }).Apply(invoke => invoke.Result),
        },
    });

    var defaultNetwork = new Gcp.Compute.Network("default", new()
    {
        Name = "my-network",
        RoutingMode = "REGIONAL",
        AutoCreateSubnetworks = false,
    });

    var defaultSubnetwork = new Gcp.Compute.Subnetwork("default", new()
    {
        Name = "my-subnetwork-name",
        Purpose = "PRIVATE",
        IpCidrRange = "10.128.0.0/20",
        Region = "us-central1",
        Network = defaultNetwork.Id,
        Role = "ACTIVE",
    });

    var proxyonlysubnet = new Gcp.Compute.Subnetwork("proxyonlysubnet", new()
    {
        Name = "my-proxy-only-subnetwork",
        Purpose = "REGIONAL_MANAGED_PROXY",
        IpCidrRange = "192.168.0.0/23",
        Region = "us-central1",
        Network = defaultNetwork.Id,
        Role = "ACTIVE",
    });

    var defaultGatewaySecurityPolicy = new Gcp.NetworkSecurity.GatewaySecurityPolicy("default", new()
    {
        Name = "my-policy-name",
        Location = "us-central1",
    });

    var defaultGatewaySecurityPolicyRule = new Gcp.NetworkSecurity.GatewaySecurityPolicyRule("default", new()
    {
        Name = "my-policyrule-name",
        Location = "us-central1",
        GatewaySecurityPolicy = defaultGatewaySecurityPolicy.Name,
        Enabled = true,
        Priority = 1,
        SessionMatcher = "host() == 'example.com'",
        BasicProfile = "ALLOW",
    });

    var defaultGateway = new Gcp.NetworkServices.Gateway("default", new()
    {
        Name = "my-gateway1",
        Location = "us-central1",
        Addresses = new[]
        {
            "10.128.0.99",
        },
        Type = "SECURE_WEB_GATEWAY",
        Ports = new[]
        {
            443,
        },
        Scope = "my-default-scope1",
        CertificateUrls = new[]
        {
            @default.Id,
        },
        GatewaySecurityPolicy = defaultGatewaySecurityPolicy.Id,
        Network = defaultNetwork.Id,
        Subnetwork = defaultSubnetwork.Id,
        DeleteSwgAutogenRouterOnDestroy = true,
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            proxyonlysubnet,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.certificatemanager.Certificate;
import com.pulumi.gcp.certificatemanager.CertificateArgs;
import com.pulumi.gcp.certificatemanager.inputs.CertificateSelfManagedArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.networksecurity.GatewaySecurityPolicy;
import com.pulumi.gcp.networksecurity.GatewaySecurityPolicyArgs;
import com.pulumi.gcp.networksecurity.GatewaySecurityPolicyRule;
import com.pulumi.gcp.networksecurity.GatewaySecurityPolicyRuleArgs;
import com.pulumi.gcp.networkservices.Gateway;
import com.pulumi.gcp.networkservices.GatewayArgs;
import com.pulumi.resources.CustomResourceOptions;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var default_ = new Certificate("default", CertificateArgs.builder()
            .name("my-certificate")
            .location("us-central1")
            .selfManaged(CertificateSelfManagedArgs.builder()
                .pemCertificate(StdFunctions.file(FileArgs.builder()
                    .input("test-fixtures/cert.pem")
                    .build()).result())
                .pemPrivateKey(StdFunctions.file(FileArgs.builder()
                    .input("test-fixtures/private-key.pem")
                    .build()).result())
                .build())
            .build());

        var defaultNetwork = new Network("defaultNetwork", NetworkArgs.builder()
            .name("my-network")
            .routingMode("REGIONAL")
            .autoCreateSubnetworks(false)
            .build());

        var defaultSubnetwork = new Subnetwork("defaultSubnetwork", SubnetworkArgs.builder()
            .name("my-subnetwork-name")
            .purpose("PRIVATE")
            .ipCidrRange("10.128.0.0/20")
            .region("us-central1")
            .network(defaultNetwork.id())
            .role("ACTIVE")
            .build());

        var proxyonlysubnet = new Subnetwork("proxyonlysubnet", SubnetworkArgs.builder()
            .name("my-proxy-only-subnetwork")
            .purpose("REGIONAL_MANAGED_PROXY")
            .ipCidrRange("192.168.0.0/23")
            .region("us-central1")
            .network(defaultNetwork.id())
            .role("ACTIVE")
            .build());

        var defaultGatewaySecurityPolicy = new GatewaySecurityPolicy("defaultGatewaySecurityPolicy", GatewaySecurityPolicyArgs.builder()
            .name("my-policy-name")
            .location("us-central1")
            .build());

        var defaultGatewaySecurityPolicyRule = new GatewaySecurityPolicyRule("defaultGatewaySecurityPolicyRule", GatewaySecurityPolicyRuleArgs.builder()
            .name("my-policyrule-name")
            .location("us-central1")
            .gatewaySecurityPolicy(defaultGatewaySecurityPolicy.name())
            .enabled(true)
            .priority(1)
            .sessionMatcher("host() == 'example.com'")
            .basicProfile("ALLOW")
            .build());

        var defaultGateway = new Gateway("defaultGateway", GatewayArgs.builder()
            .name("my-gateway1")
            .location("us-central1")
            .addresses("10.128.0.99")
            .type("SECURE_WEB_GATEWAY")
            .ports(443)
            .scope("my-default-scope1")
            .certificateUrls(default_.id())
            .gatewaySecurityPolicy(defaultGatewaySecurityPolicy.id())
            .network(defaultNetwork.id())
            .subnetwork(defaultSubnetwork.id())
            .deleteSwgAutogenRouterOnDestroy(true)
            .build(), CustomResourceOptions.builder()
                .dependsOn(proxyonlysubnet)
                .build());

    }
}
resources:
  default:
    type: gcp:certificatemanager:Certificate
    properties:
      name: my-certificate
      location: us-central1
      selfManaged:
        pemCertificate:
          fn::invoke:
            function: std:file
            arguments:
              input: test-fixtures/cert.pem
            return: result
        pemPrivateKey:
          fn::invoke:
            function: std:file
            arguments:
              input: test-fixtures/private-key.pem
            return: result
  defaultNetwork:
    type: gcp:compute:Network
    name: default
    properties:
      name: my-network
      routingMode: REGIONAL
      autoCreateSubnetworks: false
  defaultSubnetwork:
    type: gcp:compute:Subnetwork
    name: default
    properties:
      name: my-subnetwork-name
      purpose: PRIVATE
      ipCidrRange: 10.128.0.0/20
      region: us-central1
      network: ${defaultNetwork.id}
      role: ACTIVE
  proxyonlysubnet:
    type: gcp:compute:Subnetwork
    properties:
      name: my-proxy-only-subnetwork
      purpose: REGIONAL_MANAGED_PROXY
      ipCidrRange: 192.168.0.0/23
      region: us-central1
      network: ${defaultNetwork.id}
      role: ACTIVE
  defaultGatewaySecurityPolicy:
    type: gcp:networksecurity:GatewaySecurityPolicy
    name: default
    properties:
      name: my-policy-name
      location: us-central1
  defaultGatewaySecurityPolicyRule:
    type: gcp:networksecurity:GatewaySecurityPolicyRule
    name: default
    properties:
      name: my-policyrule-name
      location: us-central1
      gatewaySecurityPolicy: ${defaultGatewaySecurityPolicy.name}
      enabled: true
      priority: 1
      sessionMatcher: host() == 'example.com'
      basicProfile: ALLOW
  defaultGateway:
    type: gcp:networkservices:Gateway
    name: default
    properties:
      name: my-gateway1
      location: us-central1
      addresses:
        - 10.128.0.99
      type: SECURE_WEB_GATEWAY
      ports:
        - 443
      scope: my-default-scope1
      certificateUrls:
        - ${default.id}
      gatewaySecurityPolicy: ${defaultGatewaySecurityPolicy.id}
      network: ${defaultNetwork.id}
      subnetwork: ${defaultSubnetwork.id}
      deleteSwgAutogenRouterOnDestroy: true
    options:
      dependsOn:
        - ${proxyonlysubnet}

When type is SECURE_WEB_GATEWAY, the gateway requires VPC placement. The addresses property assigns a specific IP from the subnet range. The certificateUrls property references Certificate Manager certificates for TLS termination. The gatewaySecurityPolicy property applies filtering rules to inbound connections. The network and subnetwork properties place the gateway in your VPC. The deleteSwgAutogenRouterOnDestroy property controls cleanup of auto-generated routers when the gateway is deleted. Note the dependsOn relationship with the proxy-only subnet: secure web gateways require a REGIONAL_MANAGED_PROXY subnet to exist before creation.

Beyond these examples

These snippets focus on specific gateway-level features: open mesh and secure web gateway types, TLS certificate and security policy integration, and VPC network and subnet placement. They’re intentionally minimal rather than full traffic management solutions.

The examples may reference pre-existing infrastructure such as VPC networks and subnets (including proxy-only subnets for secure gateways), Certificate Manager certificates, and GatewaySecurityPolicy resources with rules. They focus on configuring the gateway rather than provisioning everything around it.

To keep things focused, common gateway patterns are omitted, including:

  • Server TLS policies (serverTlsPolicy)
  • Routing mode configuration (routingMode)
  • Envoy debug headers (envoyHeaders)
  • IP version selection (ipVersion)

These omissions are intentional: the goal is to illustrate how each gateway feature is wired, not provide drop-in proxy modules. See the Network Services Gateway resource reference for all available configuration options.

Let's configure GCP Network Services Gateways

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Gateway Types & Configuration
What's the difference between OPEN_MESH and SECURE_WEB_GATEWAY gateway types?
OPEN_MESH gateways listen on 0.0.0.0 (IPv4) and :: (IPv6), support multiple ports, and don’t require network configuration. SECURE_WEB_GATEWAY gateways use a specific IP address from a subnetwork and require network, subnetwork, certificateUrls, and routingMode configuration.
How does scope work for merging gateway configurations?
Gateway instances with the same scope value have their configurations merged and presented as a single configuration to the proxy/load balancer. The scope must be max 64 characters, start with a letter, and contain only letters, numbers, and hyphens.
Secure Web Gateway Setup
How do I set up a Secure Web Gateway?
You need to create: a certificate, VPC network, regular subnetwork, proxy-only subnetwork (with purpose: REGIONAL_MANAGED_PROXY), and gateway security policy. Then create the gateway with type: SECURE_WEB_GATEWAY, certificateUrls, network, subnetwork, addresses, gatewaySecurityPolicy, and routingMode. Use dependsOn: [proxyonlysubnet] to ensure proper creation order.
Why do I need a proxy-only subnetwork for Secure Web Gateway?
Secure Web Gateways require a subnetwork with purpose: REGIONAL_MANAGED_PROXY. The examples show this as a dependency using dependsOn: [proxyonlysubnet].
Can I run multiple Secure Web Gateways on the same network?
Yes, multiple SWG gateways can share the same network and subnetwork as long as they use different IP addresses.
Immutability & Lifecycle
What properties can't be changed after gateway creation?
The following properties are immutable: type, addresses, project, network, subnetwork, and scope. Changing any of these requires recreating the gateway.
What does deleteSwgAutogenRouterOnDestroy do?
When deleting a SECURE_WEB_GATEWAY, setting deleteSwgAutogenRouterOnDestroy: true also deletes the auto-generated router created with the gateway. The router is only deleted if no other SWG remains in that region and network.
Labels & Metadata
Why doesn't the labels field show all my gateway's labels?
The labels field is non-authoritative and only manages labels present in your configuration. To see all labels on the resource (including those set by other clients or services), use effectiveLabels.

Using a different cloud?

Explore networking guides for other cloud providers: