The gcp:networkconnectivity/spoke:Spoke resource, part of the Pulumi GCP provider, attaches network resources to Network Connectivity Center hubs for transitive routing. This guide focuses on three capabilities: VPC network attachment with route filtering, hybrid connectivity through VPN and Interconnect, and traffic inspection via router appliances and gateways.
Spokes reference existing hubs and network infrastructure such as VPC networks, VPN tunnels, Interconnect attachments, or Compute Engine instances. The examples are intentionally small. Combine them with your own hub topology and network architecture.
Connect a VPC network with route filtering
Most Network Connectivity Center deployments attach VPC networks to a hub, enabling transitive routing between spokes while controlling which IP ranges are advertised.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const network = new gcp.compute.Network("network", {
name: "net",
autoCreateSubnetworks: false,
});
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {
name: "hub1",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "spoke1",
location: "global",
description: "A sample spoke with a linked router appliance instance",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedVpcNetwork: {
excludeExportRanges: [
"198.51.100.0/24",
"10.10.0.0/16",
],
includeExportRanges: [
"198.51.100.0/23",
"10.0.0.0/8",
],
uri: network.selfLink,
},
});
import pulumi
import pulumi_gcp as gcp
network = gcp.compute.Network("network",
name="net",
auto_create_subnetworks=False)
basic_hub = gcp.networkconnectivity.Hub("basic_hub",
name="hub1",
description="A sample hub",
labels={
"label-two": "value-one",
})
primary = gcp.networkconnectivity.Spoke("primary",
name="spoke1",
location="global",
description="A sample spoke with a linked router appliance instance",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_vpc_network={
"exclude_export_ranges": [
"198.51.100.0/24",
"10.10.0.0/16",
],
"include_export_ranges": [
"198.51.100.0/23",
"10.0.0.0/8",
],
"uri": network.self_link,
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("net"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("hub1"),
Description: pulumi.String("A sample hub"),
Labels: pulumi.StringMap{
"label-two": pulumi.String("value-one"),
},
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "primary", &networkconnectivity.SpokeArgs{
Name: pulumi.String("spoke1"),
Location: pulumi.String("global"),
Description: pulumi.String("A sample spoke with a linked router appliance instance"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedVpcNetwork: &networkconnectivity.SpokeLinkedVpcNetworkArgs{
ExcludeExportRanges: pulumi.StringArray{
pulumi.String("198.51.100.0/24"),
pulumi.String("10.10.0.0/16"),
},
IncludeExportRanges: pulumi.StringArray{
pulumi.String("198.51.100.0/23"),
pulumi.String("10.0.0.0/8"),
},
Uri: network.SelfLink,
},
})
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 network = new Gcp.Compute.Network("network", new()
{
Name = "net",
AutoCreateSubnetworks = false,
});
var basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "hub1",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "spoke1",
Location = "global",
Description = "A sample spoke with a linked router appliance instance",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedVpcNetwork = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedVpcNetworkArgs
{
ExcludeExportRanges = new[]
{
"198.51.100.0/24",
"10.10.0.0/16",
},
IncludeExportRanges = new[]
{
"198.51.100.0/23",
"10.0.0.0/8",
},
Uri = network.SelfLink,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedVpcNetworkArgs;
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 network = new Network("network", NetworkArgs.builder()
.name("net")
.autoCreateSubnetworks(false)
.build());
var basicHub = new Hub("basicHub", HubArgs.builder()
.name("hub1")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("spoke1")
.location("global")
.description("A sample spoke with a linked router appliance instance")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedVpcNetwork(SpokeLinkedVpcNetworkArgs.builder()
.excludeExportRanges(
"198.51.100.0/24",
"10.10.0.0/16")
.includeExportRanges(
"198.51.100.0/23",
"10.0.0.0/8")
.uri(network.selfLink())
.build())
.build());
}
}
resources:
network:
type: gcp:compute:Network
properties:
name: net
autoCreateSubnetworks: false
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: hub1
description: A sample hub
labels:
label-two: value-one
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: spoke1
location: global
description: A sample spoke with a linked router appliance instance
labels:
label-one: value-one
hub: ${basicHub.id}
linkedVpcNetwork:
excludeExportRanges:
- 198.51.100.0/24
- 10.10.0.0/16
includeExportRanges:
- 198.51.100.0/23
- 10.0.0.0/8
uri: ${network.selfLink}
The linkedVpcNetwork property attaches a VPC to the hub. The uri references the VPC’s self-link. The includeExportRanges property specifies which CIDR blocks this spoke advertises to other spokes, while excludeExportRanges removes specific ranges from advertisement. This filtering prevents unwanted route propagation between spokes.
Route traffic through network virtual appliances
Organizations requiring centralized security inspection deploy router appliance instances as spokes, directing traffic through these virtual appliances before reaching destinations.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const network = new gcp.compute.Network("network", {
name: "tf-test-network_85160",
autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
name: "tf-test-subnet_92130",
ipCidrRange: "10.0.0.0/28",
region: "us-central1",
network: network.selfLink,
});
const instance = new gcp.compute.Instance("instance", {
name: "tf-test-instance_16199",
machineType: "e2-medium",
canIpForward: true,
zone: "us-central1-a",
bootDisk: {
initializeParams: {
image: "projects/debian-cloud/global/images/debian-10-buster-v20210817",
},
},
networkInterfaces: [{
subnetwork: subnetwork.name,
networkIp: "10.0.0.2",
accessConfigs: [{
networkTier: "PREMIUM",
}],
}],
});
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {
name: "tf-test-hub_21563",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "tf-test-name_25141",
location: "us-central1",
description: "A sample spoke with a linked routher appliance instance",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedRouterApplianceInstances: {
instances: [{
virtualMachine: instance.selfLink,
ipAddress: "10.0.0.2",
}],
siteToSiteDataTransfer: true,
includeImportRanges: ["ALL_IPV4_RANGES"],
},
});
import pulumi
import pulumi_gcp as gcp
network = gcp.compute.Network("network",
name="tf-test-network_85160",
auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
name="tf-test-subnet_92130",
ip_cidr_range="10.0.0.0/28",
region="us-central1",
network=network.self_link)
instance = gcp.compute.Instance("instance",
name="tf-test-instance_16199",
machine_type="e2-medium",
can_ip_forward=True,
zone="us-central1-a",
boot_disk={
"initialize_params": {
"image": "projects/debian-cloud/global/images/debian-10-buster-v20210817",
},
},
network_interfaces=[{
"subnetwork": subnetwork.name,
"network_ip": "10.0.0.2",
"access_configs": [{
"network_tier": "PREMIUM",
}],
}])
basic_hub = gcp.networkconnectivity.Hub("basic_hub",
name="tf-test-hub_21563",
description="A sample hub",
labels={
"label-two": "value-one",
})
primary = gcp.networkconnectivity.Spoke("primary",
name="tf-test-name_25141",
location="us-central1",
description="A sample spoke with a linked routher appliance instance",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_router_appliance_instances={
"instances": [{
"virtual_machine": instance.self_link,
"ip_address": "10.0.0.2",
}],
"site_to_site_data_transfer": True,
"include_import_ranges": ["ALL_IPV4_RANGES"],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("tf-test-network_85160"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
subnetwork, err := compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
Name: pulumi.String("tf-test-subnet_92130"),
IpCidrRange: pulumi.String("10.0.0.0/28"),
Region: pulumi.String("us-central1"),
Network: network.SelfLink,
})
if err != nil {
return err
}
instance, err := compute.NewInstance(ctx, "instance", &compute.InstanceArgs{
Name: pulumi.String("tf-test-instance_16199"),
MachineType: pulumi.String("e2-medium"),
CanIpForward: pulumi.Bool(true),
Zone: pulumi.String("us-central1-a"),
BootDisk: &compute.InstanceBootDiskArgs{
InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
Image: pulumi.String("projects/debian-cloud/global/images/debian-10-buster-v20210817"),
},
},
NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
&compute.InstanceNetworkInterfaceArgs{
Subnetwork: subnetwork.Name,
NetworkIp: pulumi.String("10.0.0.2"),
AccessConfigs: compute.InstanceNetworkInterfaceAccessConfigArray{
&compute.InstanceNetworkInterfaceAccessConfigArgs{
NetworkTier: pulumi.String("PREMIUM"),
},
},
},
},
})
if err != nil {
return err
}
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("tf-test-hub_21563"),
Description: pulumi.String("A sample hub"),
Labels: pulumi.StringMap{
"label-two": pulumi.String("value-one"),
},
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "primary", &networkconnectivity.SpokeArgs{
Name: pulumi.String("tf-test-name_25141"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("A sample spoke with a linked routher appliance instance"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedRouterApplianceInstances: &networkconnectivity.SpokeLinkedRouterApplianceInstancesArgs{
Instances: networkconnectivity.SpokeLinkedRouterApplianceInstancesInstanceArray{
&networkconnectivity.SpokeLinkedRouterApplianceInstancesInstanceArgs{
VirtualMachine: instance.SelfLink,
IpAddress: pulumi.String("10.0.0.2"),
},
},
SiteToSiteDataTransfer: pulumi.Bool(true),
IncludeImportRanges: pulumi.StringArray{
pulumi.String("ALL_IPV4_RANGES"),
},
},
})
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 network = new Gcp.Compute.Network("network", new()
{
Name = "tf-test-network_85160",
AutoCreateSubnetworks = false,
});
var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
{
Name = "tf-test-subnet_92130",
IpCidrRange = "10.0.0.0/28",
Region = "us-central1",
Network = network.SelfLink,
});
var instance = new Gcp.Compute.Instance("instance", new()
{
Name = "tf-test-instance_16199",
MachineType = "e2-medium",
CanIpForward = true,
Zone = "us-central1-a",
BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
{
InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
{
Image = "projects/debian-cloud/global/images/debian-10-buster-v20210817",
},
},
NetworkInterfaces = new[]
{
new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
{
Subnetwork = subnetwork.Name,
NetworkIp = "10.0.0.2",
AccessConfigs = new[]
{
new Gcp.Compute.Inputs.InstanceNetworkInterfaceAccessConfigArgs
{
NetworkTier = "PREMIUM",
},
},
},
},
});
var basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "tf-test-hub_21563",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "tf-test-name_25141",
Location = "us-central1",
Description = "A sample spoke with a linked routher appliance instance",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedRouterApplianceInstances = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedRouterApplianceInstancesArgs
{
Instances = new[]
{
new Gcp.NetworkConnectivity.Inputs.SpokeLinkedRouterApplianceInstancesInstanceArgs
{
VirtualMachine = instance.SelfLink,
IpAddress = "10.0.0.2",
},
},
SiteToSiteDataTransfer = true,
IncludeImportRanges = new[]
{
"ALL_IPV4_RANGES",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
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.compute.Instance;
import com.pulumi.gcp.compute.InstanceArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskArgs;
import com.pulumi.gcp.compute.inputs.InstanceBootDiskInitializeParamsArgs;
import com.pulumi.gcp.compute.inputs.InstanceNetworkInterfaceArgs;
import com.pulumi.gcp.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedRouterApplianceInstancesArgs;
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 network = new Network("network", NetworkArgs.builder()
.name("tf-test-network_85160")
.autoCreateSubnetworks(false)
.build());
var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
.name("tf-test-subnet_92130")
.ipCidrRange("10.0.0.0/28")
.region("us-central1")
.network(network.selfLink())
.build());
var instance = new Instance("instance", InstanceArgs.builder()
.name("tf-test-instance_16199")
.machineType("e2-medium")
.canIpForward(true)
.zone("us-central1-a")
.bootDisk(InstanceBootDiskArgs.builder()
.initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
.image("projects/debian-cloud/global/images/debian-10-buster-v20210817")
.build())
.build())
.networkInterfaces(InstanceNetworkInterfaceArgs.builder()
.subnetwork(subnetwork.name())
.networkIp("10.0.0.2")
.accessConfigs(InstanceNetworkInterfaceAccessConfigArgs.builder()
.networkTier("PREMIUM")
.build())
.build())
.build());
var basicHub = new Hub("basicHub", HubArgs.builder()
.name("tf-test-hub_21563")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("tf-test-name_25141")
.location("us-central1")
.description("A sample spoke with a linked routher appliance instance")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedRouterApplianceInstances(SpokeLinkedRouterApplianceInstancesArgs.builder()
.instances(SpokeLinkedRouterApplianceInstancesInstanceArgs.builder()
.virtualMachine(instance.selfLink())
.ipAddress("10.0.0.2")
.build())
.siteToSiteDataTransfer(true)
.includeImportRanges("ALL_IPV4_RANGES")
.build())
.build());
}
}
resources:
network:
type: gcp:compute:Network
properties:
name: tf-test-network_85160
autoCreateSubnetworks: false
subnetwork:
type: gcp:compute:Subnetwork
properties:
name: tf-test-subnet_92130
ipCidrRange: 10.0.0.0/28
region: us-central1
network: ${network.selfLink}
instance:
type: gcp:compute:Instance
properties:
name: tf-test-instance_16199
machineType: e2-medium
canIpForward: true
zone: us-central1-a
bootDisk:
initializeParams:
image: projects/debian-cloud/global/images/debian-10-buster-v20210817
networkInterfaces:
- subnetwork: ${subnetwork.name}
networkIp: 10.0.0.2
accessConfigs:
- networkTier: PREMIUM
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: tf-test-hub_21563
description: A sample hub
labels:
label-two: value-one
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: tf-test-name_25141
location: us-central1
description: A sample spoke with a linked routher appliance instance
labels:
label-one: value-one
hub: ${basicHub.id}
linkedRouterApplianceInstances:
instances:
- virtualMachine: ${instance.selfLink}
ipAddress: 10.0.0.2
siteToSiteDataTransfer: true
includeImportRanges:
- ALL_IPV4_RANGES
The linkedRouterApplianceInstances property defines one or more Compute Engine instances that act as routers. Each instance requires a virtualMachine reference and an ipAddress for routing. The siteToSiteDataTransfer property enables direct connectivity between spokes through the appliance. The instance must have IP forwarding enabled and appropriate routing software installed.
Connect on-premises networks via VPN tunnels
Hybrid cloud architectures connect on-premises data centers through VPN tunnels, with Network Connectivity Center managing routing between cloud and on-premises resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {
name: "basic-hub1",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
});
const network = new gcp.compute.Network("network", {
name: "basic-network",
autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
name: "basic-subnetwork",
ipCidrRange: "10.0.0.0/28",
region: "us-central1",
network: network.selfLink,
});
const gateway = new gcp.compute.HaVpnGateway("gateway", {
name: "vpn-gateway",
network: network.id,
});
const externalVpnGw = new gcp.compute.ExternalVpnGateway("external_vpn_gw", {
name: "external-vpn-gateway",
redundancyType: "SINGLE_IP_INTERNALLY_REDUNDANT",
description: "An externally managed VPN gateway",
interfaces: [{
id: 0,
ipAddress: "8.8.8.8",
}],
});
const router = new gcp.compute.Router("router", {
name: "external-vpn-gateway",
region: "us-central1",
network: network.name,
bgp: {
asn: 64514,
},
});
const tunnel1 = new gcp.compute.VPNTunnel("tunnel1", {
name: "tunnel1",
region: "us-central1",
vpnGateway: gateway.id,
peerExternalGateway: externalVpnGw.id,
peerExternalGatewayInterface: 0,
sharedSecret: "a secret message",
router: router.id,
vpnGatewayInterface: 0,
});
const tunnel2 = new gcp.compute.VPNTunnel("tunnel2", {
name: "tunnel2",
region: "us-central1",
vpnGateway: gateway.id,
peerExternalGateway: externalVpnGw.id,
peerExternalGatewayInterface: 0,
sharedSecret: "a secret message",
router: pulumi.interpolate` ${router.id}`,
vpnGatewayInterface: 1,
});
const routerInterface1 = new gcp.compute.RouterInterface("router_interface1", {
name: "router-interface1",
router: router.name,
region: "us-central1",
ipRange: "169.254.0.1/30",
vpnTunnel: tunnel1.name,
});
const routerPeer1 = new gcp.compute.RouterPeer("router_peer1", {
name: "router-peer1",
router: router.name,
region: "us-central1",
peerIpAddress: "169.254.0.2",
peerAsn: 64515,
advertisedRoutePriority: 100,
"interface": routerInterface1.name,
});
const routerInterface2 = new gcp.compute.RouterInterface("router_interface2", {
name: "router-interface2",
router: router.name,
region: "us-central1",
ipRange: "169.254.1.1/30",
vpnTunnel: tunnel2.name,
});
const routerPeer2 = new gcp.compute.RouterPeer("router_peer2", {
name: "router-peer2",
router: router.name,
region: "us-central1",
peerIpAddress: "169.254.1.2",
peerAsn: 64515,
advertisedRoutePriority: 100,
"interface": routerInterface2.name,
});
const tunnel1Spoke = new gcp.networkconnectivity.Spoke("tunnel1", {
name: "vpn-tunnel-1-spoke",
location: "us-central1",
description: "A sample spoke with a linked VPN Tunnel",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedVpnTunnels: {
uris: [tunnel1.selfLink],
siteToSiteDataTransfer: true,
includeImportRanges: ["ALL_IPV4_RANGES"],
},
});
const tunnel2Spoke = new gcp.networkconnectivity.Spoke("tunnel2", {
name: "vpn-tunnel-2-spoke",
location: "us-central1",
description: "A sample spoke with a linked VPN Tunnel",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedVpnTunnels: {
uris: [tunnel2.selfLink],
siteToSiteDataTransfer: true,
includeImportRanges: ["ALL_IPV4_RANGES"],
},
});
import pulumi
import pulumi_gcp as gcp
basic_hub = gcp.networkconnectivity.Hub("basic_hub",
name="basic-hub1",
description="A sample hub",
labels={
"label-two": "value-one",
})
network = gcp.compute.Network("network",
name="basic-network",
auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
name="basic-subnetwork",
ip_cidr_range="10.0.0.0/28",
region="us-central1",
network=network.self_link)
gateway = gcp.compute.HaVpnGateway("gateway",
name="vpn-gateway",
network=network.id)
external_vpn_gw = gcp.compute.ExternalVpnGateway("external_vpn_gw",
name="external-vpn-gateway",
redundancy_type="SINGLE_IP_INTERNALLY_REDUNDANT",
description="An externally managed VPN gateway",
interfaces=[{
"id": 0,
"ip_address": "8.8.8.8",
}])
router = gcp.compute.Router("router",
name="external-vpn-gateway",
region="us-central1",
network=network.name,
bgp={
"asn": 64514,
})
tunnel1 = gcp.compute.VPNTunnel("tunnel1",
name="tunnel1",
region="us-central1",
vpn_gateway=gateway.id,
peer_external_gateway=external_vpn_gw.id,
peer_external_gateway_interface=0,
shared_secret="a secret message",
router=router.id,
vpn_gateway_interface=0)
tunnel2 = gcp.compute.VPNTunnel("tunnel2",
name="tunnel2",
region="us-central1",
vpn_gateway=gateway.id,
peer_external_gateway=external_vpn_gw.id,
peer_external_gateway_interface=0,
shared_secret="a secret message",
router=router.id.apply(lambda id: f" {id}"),
vpn_gateway_interface=1)
router_interface1 = gcp.compute.RouterInterface("router_interface1",
name="router-interface1",
router=router.name,
region="us-central1",
ip_range="169.254.0.1/30",
vpn_tunnel=tunnel1.name)
router_peer1 = gcp.compute.RouterPeer("router_peer1",
name="router-peer1",
router=router.name,
region="us-central1",
peer_ip_address="169.254.0.2",
peer_asn=64515,
advertised_route_priority=100,
interface=router_interface1.name)
router_interface2 = gcp.compute.RouterInterface("router_interface2",
name="router-interface2",
router=router.name,
region="us-central1",
ip_range="169.254.1.1/30",
vpn_tunnel=tunnel2.name)
router_peer2 = gcp.compute.RouterPeer("router_peer2",
name="router-peer2",
router=router.name,
region="us-central1",
peer_ip_address="169.254.1.2",
peer_asn=64515,
advertised_route_priority=100,
interface=router_interface2.name)
tunnel1_spoke = gcp.networkconnectivity.Spoke("tunnel1",
name="vpn-tunnel-1-spoke",
location="us-central1",
description="A sample spoke with a linked VPN Tunnel",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_vpn_tunnels={
"uris": [tunnel1.self_link],
"site_to_site_data_transfer": True,
"include_import_ranges": ["ALL_IPV4_RANGES"],
})
tunnel2_spoke = gcp.networkconnectivity.Spoke("tunnel2",
name="vpn-tunnel-2-spoke",
location="us-central1",
description="A sample spoke with a linked VPN Tunnel",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_vpn_tunnels={
"uris": [tunnel2.self_link],
"site_to_site_data_transfer": True,
"include_import_ranges": ["ALL_IPV4_RANGES"],
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("basic-hub1"),
Description: pulumi.String("A sample hub"),
Labels: pulumi.StringMap{
"label-two": pulumi.String("value-one"),
},
})
if err != nil {
return err
}
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("basic-network"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
_, err = compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
Name: pulumi.String("basic-subnetwork"),
IpCidrRange: pulumi.String("10.0.0.0/28"),
Region: pulumi.String("us-central1"),
Network: network.SelfLink,
})
if err != nil {
return err
}
gateway, err := compute.NewHaVpnGateway(ctx, "gateway", &compute.HaVpnGatewayArgs{
Name: pulumi.String("vpn-gateway"),
Network: network.ID(),
})
if err != nil {
return err
}
externalVpnGw, err := compute.NewExternalVpnGateway(ctx, "external_vpn_gw", &compute.ExternalVpnGatewayArgs{
Name: pulumi.String("external-vpn-gateway"),
RedundancyType: pulumi.String("SINGLE_IP_INTERNALLY_REDUNDANT"),
Description: pulumi.String("An externally managed VPN gateway"),
Interfaces: compute.ExternalVpnGatewayInterfaceArray{
&compute.ExternalVpnGatewayInterfaceArgs{
Id: pulumi.Int(0),
IpAddress: pulumi.String("8.8.8.8"),
},
},
})
if err != nil {
return err
}
router, err := compute.NewRouter(ctx, "router", &compute.RouterArgs{
Name: pulumi.String("external-vpn-gateway"),
Region: pulumi.String("us-central1"),
Network: network.Name,
Bgp: &compute.RouterBgpArgs{
Asn: pulumi.Int(64514),
},
})
if err != nil {
return err
}
tunnel1, err := compute.NewVPNTunnel(ctx, "tunnel1", &compute.VPNTunnelArgs{
Name: pulumi.String("tunnel1"),
Region: pulumi.String("us-central1"),
VpnGateway: gateway.ID(),
PeerExternalGateway: externalVpnGw.ID(),
PeerExternalGatewayInterface: pulumi.Int(0),
SharedSecret: pulumi.String("a secret message"),
Router: router.ID(),
VpnGatewayInterface: pulumi.Int(0),
})
if err != nil {
return err
}
tunnel2, err := compute.NewVPNTunnel(ctx, "tunnel2", &compute.VPNTunnelArgs{
Name: pulumi.String("tunnel2"),
Region: pulumi.String("us-central1"),
VpnGateway: gateway.ID(),
PeerExternalGateway: externalVpnGw.ID(),
PeerExternalGatewayInterface: pulumi.Int(0),
SharedSecret: pulumi.String("a secret message"),
Router: router.ID().ApplyT(func(id string) (string, error) {
return fmt.Sprintf(" %v", id), nil
}).(pulumi.StringOutput),
VpnGatewayInterface: pulumi.Int(1),
})
if err != nil {
return err
}
routerInterface1, err := compute.NewRouterInterface(ctx, "router_interface1", &compute.RouterInterfaceArgs{
Name: pulumi.String("router-interface1"),
Router: router.Name,
Region: pulumi.String("us-central1"),
IpRange: pulumi.String("169.254.0.1/30"),
VpnTunnel: tunnel1.Name,
})
if err != nil {
return err
}
_, err = compute.NewRouterPeer(ctx, "router_peer1", &compute.RouterPeerArgs{
Name: pulumi.String("router-peer1"),
Router: router.Name,
Region: pulumi.String("us-central1"),
PeerIpAddress: pulumi.String("169.254.0.2"),
PeerAsn: pulumi.Int(64515),
AdvertisedRoutePriority: pulumi.Int(100),
Interface: routerInterface1.Name,
})
if err != nil {
return err
}
routerInterface2, err := compute.NewRouterInterface(ctx, "router_interface2", &compute.RouterInterfaceArgs{
Name: pulumi.String("router-interface2"),
Router: router.Name,
Region: pulumi.String("us-central1"),
IpRange: pulumi.String("169.254.1.1/30"),
VpnTunnel: tunnel2.Name,
})
if err != nil {
return err
}
_, err = compute.NewRouterPeer(ctx, "router_peer2", &compute.RouterPeerArgs{
Name: pulumi.String("router-peer2"),
Router: router.Name,
Region: pulumi.String("us-central1"),
PeerIpAddress: pulumi.String("169.254.1.2"),
PeerAsn: pulumi.Int(64515),
AdvertisedRoutePriority: pulumi.Int(100),
Interface: routerInterface2.Name,
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "tunnel1", &networkconnectivity.SpokeArgs{
Name: pulumi.String("vpn-tunnel-1-spoke"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("A sample spoke with a linked VPN Tunnel"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedVpnTunnels: &networkconnectivity.SpokeLinkedVpnTunnelsArgs{
Uris: pulumi.StringArray{
tunnel1.SelfLink,
},
SiteToSiteDataTransfer: pulumi.Bool(true),
IncludeImportRanges: pulumi.StringArray{
pulumi.String("ALL_IPV4_RANGES"),
},
},
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "tunnel2", &networkconnectivity.SpokeArgs{
Name: pulumi.String("vpn-tunnel-2-spoke"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("A sample spoke with a linked VPN Tunnel"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedVpnTunnels: &networkconnectivity.SpokeLinkedVpnTunnelsArgs{
Uris: pulumi.StringArray{
tunnel2.SelfLink,
},
SiteToSiteDataTransfer: pulumi.Bool(true),
IncludeImportRanges: pulumi.StringArray{
pulumi.String("ALL_IPV4_RANGES"),
},
},
})
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 basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "basic-hub1",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
});
var network = new Gcp.Compute.Network("network", new()
{
Name = "basic-network",
AutoCreateSubnetworks = false,
});
var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
{
Name = "basic-subnetwork",
IpCidrRange = "10.0.0.0/28",
Region = "us-central1",
Network = network.SelfLink,
});
var gateway = new Gcp.Compute.HaVpnGateway("gateway", new()
{
Name = "vpn-gateway",
Network = network.Id,
});
var externalVpnGw = new Gcp.Compute.ExternalVpnGateway("external_vpn_gw", new()
{
Name = "external-vpn-gateway",
RedundancyType = "SINGLE_IP_INTERNALLY_REDUNDANT",
Description = "An externally managed VPN gateway",
Interfaces = new[]
{
new Gcp.Compute.Inputs.ExternalVpnGatewayInterfaceArgs
{
Id = 0,
IpAddress = "8.8.8.8",
},
},
});
var router = new Gcp.Compute.Router("router", new()
{
Name = "external-vpn-gateway",
Region = "us-central1",
Network = network.Name,
Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
{
Asn = 64514,
},
});
var tunnel1 = new Gcp.Compute.VPNTunnel("tunnel1", new()
{
Name = "tunnel1",
Region = "us-central1",
VpnGateway = gateway.Id,
PeerExternalGateway = externalVpnGw.Id,
PeerExternalGatewayInterface = 0,
SharedSecret = "a secret message",
Router = router.Id,
VpnGatewayInterface = 0,
});
var tunnel2 = new Gcp.Compute.VPNTunnel("tunnel2", new()
{
Name = "tunnel2",
Region = "us-central1",
VpnGateway = gateway.Id,
PeerExternalGateway = externalVpnGw.Id,
PeerExternalGatewayInterface = 0,
SharedSecret = "a secret message",
Router = router.Id.Apply(id => $" {id}"),
VpnGatewayInterface = 1,
});
var routerInterface1 = new Gcp.Compute.RouterInterface("router_interface1", new()
{
Name = "router-interface1",
Router = router.Name,
Region = "us-central1",
IpRange = "169.254.0.1/30",
VpnTunnel = tunnel1.Name,
});
var routerPeer1 = new Gcp.Compute.RouterPeer("router_peer1", new()
{
Name = "router-peer1",
Router = router.Name,
Region = "us-central1",
PeerIpAddress = "169.254.0.2",
PeerAsn = 64515,
AdvertisedRoutePriority = 100,
Interface = routerInterface1.Name,
});
var routerInterface2 = new Gcp.Compute.RouterInterface("router_interface2", new()
{
Name = "router-interface2",
Router = router.Name,
Region = "us-central1",
IpRange = "169.254.1.1/30",
VpnTunnel = tunnel2.Name,
});
var routerPeer2 = new Gcp.Compute.RouterPeer("router_peer2", new()
{
Name = "router-peer2",
Router = router.Name,
Region = "us-central1",
PeerIpAddress = "169.254.1.2",
PeerAsn = 64515,
AdvertisedRoutePriority = 100,
Interface = routerInterface2.Name,
});
var tunnel1Spoke = new Gcp.NetworkConnectivity.Spoke("tunnel1", new()
{
Name = "vpn-tunnel-1-spoke",
Location = "us-central1",
Description = "A sample spoke with a linked VPN Tunnel",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedVpnTunnels = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedVpnTunnelsArgs
{
Uris = new[]
{
tunnel1.SelfLink,
},
SiteToSiteDataTransfer = true,
IncludeImportRanges = new[]
{
"ALL_IPV4_RANGES",
},
},
});
var tunnel2Spoke = new Gcp.NetworkConnectivity.Spoke("tunnel2", new()
{
Name = "vpn-tunnel-2-spoke",
Location = "us-central1",
Description = "A sample spoke with a linked VPN Tunnel",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedVpnTunnels = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedVpnTunnelsArgs
{
Uris = new[]
{
tunnel2.SelfLink,
},
SiteToSiteDataTransfer = true,
IncludeImportRanges = new[]
{
"ALL_IPV4_RANGES",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
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.compute.HaVpnGateway;
import com.pulumi.gcp.compute.HaVpnGatewayArgs;
import com.pulumi.gcp.compute.ExternalVpnGateway;
import com.pulumi.gcp.compute.ExternalVpnGatewayArgs;
import com.pulumi.gcp.compute.inputs.ExternalVpnGatewayInterfaceArgs;
import com.pulumi.gcp.compute.Router;
import com.pulumi.gcp.compute.RouterArgs;
import com.pulumi.gcp.compute.inputs.RouterBgpArgs;
import com.pulumi.gcp.compute.VPNTunnel;
import com.pulumi.gcp.compute.VPNTunnelArgs;
import com.pulumi.gcp.compute.RouterInterface;
import com.pulumi.gcp.compute.RouterInterfaceArgs;
import com.pulumi.gcp.compute.RouterPeer;
import com.pulumi.gcp.compute.RouterPeerArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedVpnTunnelsArgs;
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 basicHub = new Hub("basicHub", HubArgs.builder()
.name("basic-hub1")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.build());
var network = new Network("network", NetworkArgs.builder()
.name("basic-network")
.autoCreateSubnetworks(false)
.build());
var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
.name("basic-subnetwork")
.ipCidrRange("10.0.0.0/28")
.region("us-central1")
.network(network.selfLink())
.build());
var gateway = new HaVpnGateway("gateway", HaVpnGatewayArgs.builder()
.name("vpn-gateway")
.network(network.id())
.build());
var externalVpnGw = new ExternalVpnGateway("externalVpnGw", ExternalVpnGatewayArgs.builder()
.name("external-vpn-gateway")
.redundancyType("SINGLE_IP_INTERNALLY_REDUNDANT")
.description("An externally managed VPN gateway")
.interfaces(ExternalVpnGatewayInterfaceArgs.builder()
.id(0)
.ipAddress("8.8.8.8")
.build())
.build());
var router = new Router("router", RouterArgs.builder()
.name("external-vpn-gateway")
.region("us-central1")
.network(network.name())
.bgp(RouterBgpArgs.builder()
.asn(64514)
.build())
.build());
var tunnel1 = new VPNTunnel("tunnel1", VPNTunnelArgs.builder()
.name("tunnel1")
.region("us-central1")
.vpnGateway(gateway.id())
.peerExternalGateway(externalVpnGw.id())
.peerExternalGatewayInterface(0)
.sharedSecret("a secret message")
.router(router.id())
.vpnGatewayInterface(0)
.build());
var tunnel2 = new VPNTunnel("tunnel2", VPNTunnelArgs.builder()
.name("tunnel2")
.region("us-central1")
.vpnGateway(gateway.id())
.peerExternalGateway(externalVpnGw.id())
.peerExternalGatewayInterface(0)
.sharedSecret("a secret message")
.router(router.id().applyValue(_id -> String.format(" %s", _id)))
.vpnGatewayInterface(1)
.build());
var routerInterface1 = new RouterInterface("routerInterface1", RouterInterfaceArgs.builder()
.name("router-interface1")
.router(router.name())
.region("us-central1")
.ipRange("169.254.0.1/30")
.vpnTunnel(tunnel1.name())
.build());
var routerPeer1 = new RouterPeer("routerPeer1", RouterPeerArgs.builder()
.name("router-peer1")
.router(router.name())
.region("us-central1")
.peerIpAddress("169.254.0.2")
.peerAsn(64515)
.advertisedRoutePriority(100)
.interface_(routerInterface1.name())
.build());
var routerInterface2 = new RouterInterface("routerInterface2", RouterInterfaceArgs.builder()
.name("router-interface2")
.router(router.name())
.region("us-central1")
.ipRange("169.254.1.1/30")
.vpnTunnel(tunnel2.name())
.build());
var routerPeer2 = new RouterPeer("routerPeer2", RouterPeerArgs.builder()
.name("router-peer2")
.router(router.name())
.region("us-central1")
.peerIpAddress("169.254.1.2")
.peerAsn(64515)
.advertisedRoutePriority(100)
.interface_(routerInterface2.name())
.build());
var tunnel1Spoke = new Spoke("tunnel1Spoke", SpokeArgs.builder()
.name("vpn-tunnel-1-spoke")
.location("us-central1")
.description("A sample spoke with a linked VPN Tunnel")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedVpnTunnels(SpokeLinkedVpnTunnelsArgs.builder()
.uris(tunnel1.selfLink())
.siteToSiteDataTransfer(true)
.includeImportRanges("ALL_IPV4_RANGES")
.build())
.build());
var tunnel2Spoke = new Spoke("tunnel2Spoke", SpokeArgs.builder()
.name("vpn-tunnel-2-spoke")
.location("us-central1")
.description("A sample spoke with a linked VPN Tunnel")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedVpnTunnels(SpokeLinkedVpnTunnelsArgs.builder()
.uris(tunnel2.selfLink())
.siteToSiteDataTransfer(true)
.includeImportRanges("ALL_IPV4_RANGES")
.build())
.build());
}
}
resources:
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: basic-hub1
description: A sample hub
labels:
label-two: value-one
network:
type: gcp:compute:Network
properties:
name: basic-network
autoCreateSubnetworks: false
subnetwork:
type: gcp:compute:Subnetwork
properties:
name: basic-subnetwork
ipCidrRange: 10.0.0.0/28
region: us-central1
network: ${network.selfLink}
gateway:
type: gcp:compute:HaVpnGateway
properties:
name: vpn-gateway
network: ${network.id}
externalVpnGw:
type: gcp:compute:ExternalVpnGateway
name: external_vpn_gw
properties:
name: external-vpn-gateway
redundancyType: SINGLE_IP_INTERNALLY_REDUNDANT
description: An externally managed VPN gateway
interfaces:
- id: 0
ipAddress: 8.8.8.8
router:
type: gcp:compute:Router
properties:
name: external-vpn-gateway
region: us-central1
network: ${network.name}
bgp:
asn: 64514
tunnel1:
type: gcp:compute:VPNTunnel
properties:
name: tunnel1
region: us-central1
vpnGateway: ${gateway.id}
peerExternalGateway: ${externalVpnGw.id}
peerExternalGatewayInterface: 0
sharedSecret: a secret message
router: ${router.id}
vpnGatewayInterface: 0
tunnel2:
type: gcp:compute:VPNTunnel
properties:
name: tunnel2
region: us-central1
vpnGateway: ${gateway.id}
peerExternalGateway: ${externalVpnGw.id}
peerExternalGatewayInterface: 0
sharedSecret: a secret message
router: ' ${router.id}'
vpnGatewayInterface: 1
routerInterface1:
type: gcp:compute:RouterInterface
name: router_interface1
properties:
name: router-interface1
router: ${router.name}
region: us-central1
ipRange: 169.254.0.1/30
vpnTunnel: ${tunnel1.name}
routerPeer1:
type: gcp:compute:RouterPeer
name: router_peer1
properties:
name: router-peer1
router: ${router.name}
region: us-central1
peerIpAddress: 169.254.0.2
peerAsn: 64515
advertisedRoutePriority: 100
interface: ${routerInterface1.name}
routerInterface2:
type: gcp:compute:RouterInterface
name: router_interface2
properties:
name: router-interface2
router: ${router.name}
region: us-central1
ipRange: 169.254.1.1/30
vpnTunnel: ${tunnel2.name}
routerPeer2:
type: gcp:compute:RouterPeer
name: router_peer2
properties:
name: router-peer2
router: ${router.name}
region: us-central1
peerIpAddress: 169.254.1.2
peerAsn: 64515
advertisedRoutePriority: 100
interface: ${routerInterface2.name}
tunnel1Spoke:
type: gcp:networkconnectivity:Spoke
name: tunnel1
properties:
name: vpn-tunnel-1-spoke
location: us-central1
description: A sample spoke with a linked VPN Tunnel
labels:
label-one: value-one
hub: ${basicHub.id}
linkedVpnTunnels:
uris:
- ${tunnel1.selfLink}
siteToSiteDataTransfer: true
includeImportRanges:
- ALL_IPV4_RANGES
tunnel2Spoke:
type: gcp:networkconnectivity:Spoke
name: tunnel2
properties:
name: vpn-tunnel-2-spoke
location: us-central1
description: A sample spoke with a linked VPN Tunnel
labels:
label-one: value-one
hub: ${basicHub.id}
linkedVpnTunnels:
uris:
- ${tunnel2.selfLink}
siteToSiteDataTransfer: true
includeImportRanges:
- ALL_IPV4_RANGES
The linkedVpnTunnels property attaches one or more VPN tunnels to the hub. The uris array references tunnel self-links. The includeImportRanges property controls which routes from the tunnel are imported into the hub; ALL_IPV4_RANGES accepts all advertised routes. BGP configuration on the Cloud Router handles route exchange with the on-premises network.
Connect via Cloud Interconnect attachments
Enterprises with dedicated physical connections use Cloud Interconnect attachments for higher bandwidth and lower latency than VPN tunnels.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {
name: "basic-hub1",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
});
const network = new gcp.compute.Network("network", {
name: "basic-network",
autoCreateSubnetworks: false,
});
const router = new gcp.compute.Router("router", {
name: "external-vpn-gateway",
region: "us-central1",
network: network.name,
bgp: {
asn: 16550,
},
});
const interconnect_attachment = new gcp.compute.InterconnectAttachment("interconnect-attachment", {
name: "partner-interconnect1",
edgeAvailabilityDomain: "AVAILABILITY_DOMAIN_1",
type: "PARTNER",
router: router.id,
mtu: "1500",
region: "us-central1",
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "interconnect-attachment-spoke",
location: "us-central1",
description: "A sample spoke with a linked Interconnect Attachment",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedInterconnectAttachments: {
uris: [interconnect_attachment.selfLink],
siteToSiteDataTransfer: true,
includeImportRanges: ["ALL_IPV4_RANGES"],
},
});
import pulumi
import pulumi_gcp as gcp
basic_hub = gcp.networkconnectivity.Hub("basic_hub",
name="basic-hub1",
description="A sample hub",
labels={
"label-two": "value-one",
})
network = gcp.compute.Network("network",
name="basic-network",
auto_create_subnetworks=False)
router = gcp.compute.Router("router",
name="external-vpn-gateway",
region="us-central1",
network=network.name,
bgp={
"asn": 16550,
})
interconnect_attachment = gcp.compute.InterconnectAttachment("interconnect-attachment",
name="partner-interconnect1",
edge_availability_domain="AVAILABILITY_DOMAIN_1",
type="PARTNER",
router=router.id,
mtu="1500",
region="us-central1")
primary = gcp.networkconnectivity.Spoke("primary",
name="interconnect-attachment-spoke",
location="us-central1",
description="A sample spoke with a linked Interconnect Attachment",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_interconnect_attachments={
"uris": [interconnect_attachment.self_link],
"site_to_site_data_transfer": True,
"include_import_ranges": ["ALL_IPV4_RANGES"],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("basic-hub1"),
Description: pulumi.String("A sample hub"),
Labels: pulumi.StringMap{
"label-two": pulumi.String("value-one"),
},
})
if err != nil {
return err
}
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("basic-network"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
router, err := compute.NewRouter(ctx, "router", &compute.RouterArgs{
Name: pulumi.String("external-vpn-gateway"),
Region: pulumi.String("us-central1"),
Network: network.Name,
Bgp: &compute.RouterBgpArgs{
Asn: pulumi.Int(16550),
},
})
if err != nil {
return err
}
interconnect_attachment, err := compute.NewInterconnectAttachment(ctx, "interconnect-attachment", &compute.InterconnectAttachmentArgs{
Name: pulumi.String("partner-interconnect1"),
EdgeAvailabilityDomain: pulumi.String("AVAILABILITY_DOMAIN_1"),
Type: pulumi.String("PARTNER"),
Router: router.ID(),
Mtu: pulumi.String("1500"),
Region: pulumi.String("us-central1"),
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "primary", &networkconnectivity.SpokeArgs{
Name: pulumi.String("interconnect-attachment-spoke"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("A sample spoke with a linked Interconnect Attachment"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedInterconnectAttachments: &networkconnectivity.SpokeLinkedInterconnectAttachmentsArgs{
Uris: pulumi.StringArray{
interconnect_attachment.SelfLink,
},
SiteToSiteDataTransfer: pulumi.Bool(true),
IncludeImportRanges: pulumi.StringArray{
pulumi.String("ALL_IPV4_RANGES"),
},
},
})
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 basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "basic-hub1",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
});
var network = new Gcp.Compute.Network("network", new()
{
Name = "basic-network",
AutoCreateSubnetworks = false,
});
var router = new Gcp.Compute.Router("router", new()
{
Name = "external-vpn-gateway",
Region = "us-central1",
Network = network.Name,
Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
{
Asn = 16550,
},
});
var interconnect_attachment = new Gcp.Compute.InterconnectAttachment("interconnect-attachment", new()
{
Name = "partner-interconnect1",
EdgeAvailabilityDomain = "AVAILABILITY_DOMAIN_1",
Type = "PARTNER",
Router = router.Id,
Mtu = "1500",
Region = "us-central1",
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "interconnect-attachment-spoke",
Location = "us-central1",
Description = "A sample spoke with a linked Interconnect Attachment",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedInterconnectAttachments = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedInterconnectAttachmentsArgs
{
Uris = new[]
{
interconnect_attachment.SelfLink,
},
SiteToSiteDataTransfer = true,
IncludeImportRanges = new[]
{
"ALL_IPV4_RANGES",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.Router;
import com.pulumi.gcp.compute.RouterArgs;
import com.pulumi.gcp.compute.inputs.RouterBgpArgs;
import com.pulumi.gcp.compute.InterconnectAttachment;
import com.pulumi.gcp.compute.InterconnectAttachmentArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedInterconnectAttachmentsArgs;
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 basicHub = new Hub("basicHub", HubArgs.builder()
.name("basic-hub1")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.build());
var network = new Network("network", NetworkArgs.builder()
.name("basic-network")
.autoCreateSubnetworks(false)
.build());
var router = new Router("router", RouterArgs.builder()
.name("external-vpn-gateway")
.region("us-central1")
.network(network.name())
.bgp(RouterBgpArgs.builder()
.asn(16550)
.build())
.build());
var interconnect_attachment = new InterconnectAttachment("interconnect-attachment", InterconnectAttachmentArgs.builder()
.name("partner-interconnect1")
.edgeAvailabilityDomain("AVAILABILITY_DOMAIN_1")
.type("PARTNER")
.router(router.id())
.mtu("1500")
.region("us-central1")
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("interconnect-attachment-spoke")
.location("us-central1")
.description("A sample spoke with a linked Interconnect Attachment")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedInterconnectAttachments(SpokeLinkedInterconnectAttachmentsArgs.builder()
.uris(interconnect_attachment.selfLink())
.siteToSiteDataTransfer(true)
.includeImportRanges("ALL_IPV4_RANGES")
.build())
.build());
}
}
resources:
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: basic-hub1
description: A sample hub
labels:
label-two: value-one
network:
type: gcp:compute:Network
properties:
name: basic-network
autoCreateSubnetworks: false
router:
type: gcp:compute:Router
properties:
name: external-vpn-gateway
region: us-central1
network: ${network.name}
bgp:
asn: 16550
interconnect-attachment:
type: gcp:compute:InterconnectAttachment
properties:
name: partner-interconnect1
edgeAvailabilityDomain: AVAILABILITY_DOMAIN_1
type: PARTNER
router: ${router.id}
mtu: 1500
region: us-central1
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: interconnect-attachment-spoke
location: us-central1
description: A sample spoke with a linked Interconnect Attachment
labels:
label-one: value-one
hub: ${basicHub.id}
linkedInterconnectAttachments:
uris:
- ${["interconnect-attachment"].selfLink}
siteToSiteDataTransfer: true
includeImportRanges:
- ALL_IPV4_RANGES
The linkedInterconnectAttachments property attaches VLAN attachments to the hub. Like VPN tunnels, these attachments use BGP for route exchange. The siteToSiteDataTransfer property enables direct connectivity between spokes through the Interconnect. Interconnect attachments provide dedicated bandwidth and consistent latency for production workloads.
Connect service producer VPC networks
Managed services that use VPC Service Controls create producer VPC networks through VPC peering. Network Connectivity Center can attach these producer networks to enable routing to other resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const network = new gcp.compute.Network("network", {
name: "net-spoke",
autoCreateSubnetworks: false,
});
const address = new gcp.compute.GlobalAddress("address", {
name: "test-address",
purpose: "VPC_PEERING",
addressType: "INTERNAL",
prefixLength: 16,
network: network.id,
});
const peering = new gcp.servicenetworking.Connection("peering", {
network: network.id,
service: "servicenetworking.googleapis.com",
reservedPeeringRanges: [address.name],
});
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {name: "hub-basic"});
const linkedVpcSpoke = new gcp.networkconnectivity.Spoke("linked_vpc_spoke", {
name: "vpc-spoke",
location: "global",
hub: basicHub.id,
linkedVpcNetwork: {
uri: network.selfLink,
},
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "producer-spoke",
location: "global",
description: "A sample spoke with a linked router appliance instance",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
linkedProducerVpcNetwork: {
network: network.name,
peering: peering.peering,
excludeExportRanges: [
"198.51.100.0/24",
"10.10.0.0/16",
],
},
}, {
dependsOn: [linkedVpcSpoke],
});
import pulumi
import pulumi_gcp as gcp
network = gcp.compute.Network("network",
name="net-spoke",
auto_create_subnetworks=False)
address = gcp.compute.GlobalAddress("address",
name="test-address",
purpose="VPC_PEERING",
address_type="INTERNAL",
prefix_length=16,
network=network.id)
peering = gcp.servicenetworking.Connection("peering",
network=network.id,
service="servicenetworking.googleapis.com",
reserved_peering_ranges=[address.name])
basic_hub = gcp.networkconnectivity.Hub("basic_hub", name="hub-basic")
linked_vpc_spoke = gcp.networkconnectivity.Spoke("linked_vpc_spoke",
name="vpc-spoke",
location="global",
hub=basic_hub.id,
linked_vpc_network={
"uri": network.self_link,
})
primary = gcp.networkconnectivity.Spoke("primary",
name="producer-spoke",
location="global",
description="A sample spoke with a linked router appliance instance",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
linked_producer_vpc_network={
"network": network.name,
"peering": peering.peering,
"exclude_export_ranges": [
"198.51.100.0/24",
"10.10.0.0/16",
],
},
opts = pulumi.ResourceOptions(depends_on=[linked_vpc_spoke]))
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/servicenetworking"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("net-spoke"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
address, err := compute.NewGlobalAddress(ctx, "address", &compute.GlobalAddressArgs{
Name: pulumi.String("test-address"),
Purpose: pulumi.String("VPC_PEERING"),
AddressType: pulumi.String("INTERNAL"),
PrefixLength: pulumi.Int(16),
Network: network.ID(),
})
if err != nil {
return err
}
peering, err := servicenetworking.NewConnection(ctx, "peering", &servicenetworking.ConnectionArgs{
Network: network.ID(),
Service: pulumi.String("servicenetworking.googleapis.com"),
ReservedPeeringRanges: pulumi.StringArray{
address.Name,
},
})
if err != nil {
return err
}
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("hub-basic"),
})
if err != nil {
return err
}
linkedVpcSpoke, err := networkconnectivity.NewSpoke(ctx, "linked_vpc_spoke", &networkconnectivity.SpokeArgs{
Name: pulumi.String("vpc-spoke"),
Location: pulumi.String("global"),
Hub: basicHub.ID(),
LinkedVpcNetwork: &networkconnectivity.SpokeLinkedVpcNetworkArgs{
Uri: network.SelfLink,
},
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "primary", &networkconnectivity.SpokeArgs{
Name: pulumi.String("producer-spoke"),
Location: pulumi.String("global"),
Description: pulumi.String("A sample spoke with a linked router appliance instance"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
LinkedProducerVpcNetwork: &networkconnectivity.SpokeLinkedProducerVpcNetworkArgs{
Network: network.Name,
Peering: peering.Peering,
ExcludeExportRanges: pulumi.StringArray{
pulumi.String("198.51.100.0/24"),
pulumi.String("10.10.0.0/16"),
},
},
}, pulumi.DependsOn([]pulumi.Resource{
linkedVpcSpoke,
}))
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 network = new Gcp.Compute.Network("network", new()
{
Name = "net-spoke",
AutoCreateSubnetworks = false,
});
var address = new Gcp.Compute.GlobalAddress("address", new()
{
Name = "test-address",
Purpose = "VPC_PEERING",
AddressType = "INTERNAL",
PrefixLength = 16,
Network = network.Id,
});
var peering = new Gcp.ServiceNetworking.Connection("peering", new()
{
Network = network.Id,
Service = "servicenetworking.googleapis.com",
ReservedPeeringRanges = new[]
{
address.Name,
},
});
var basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "hub-basic",
});
var linkedVpcSpoke = new Gcp.NetworkConnectivity.Spoke("linked_vpc_spoke", new()
{
Name = "vpc-spoke",
Location = "global",
Hub = basicHub.Id,
LinkedVpcNetwork = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedVpcNetworkArgs
{
Uri = network.SelfLink,
},
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "producer-spoke",
Location = "global",
Description = "A sample spoke with a linked router appliance instance",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
LinkedProducerVpcNetwork = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedProducerVpcNetworkArgs
{
Network = network.Name,
Peering = peering.Peering,
ExcludeExportRanges = new[]
{
"198.51.100.0/24",
"10.10.0.0/16",
},
},
}, new CustomResourceOptions
{
DependsOn =
{
linkedVpcSpoke,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.GlobalAddress;
import com.pulumi.gcp.compute.GlobalAddressArgs;
import com.pulumi.gcp.servicenetworking.Connection;
import com.pulumi.gcp.servicenetworking.ConnectionArgs;
import com.pulumi.gcp.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedVpcNetworkArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeLinkedProducerVpcNetworkArgs;
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 network = new Network("network", NetworkArgs.builder()
.name("net-spoke")
.autoCreateSubnetworks(false)
.build());
var address = new GlobalAddress("address", GlobalAddressArgs.builder()
.name("test-address")
.purpose("VPC_PEERING")
.addressType("INTERNAL")
.prefixLength(16)
.network(network.id())
.build());
var peering = new Connection("peering", ConnectionArgs.builder()
.network(network.id())
.service("servicenetworking.googleapis.com")
.reservedPeeringRanges(address.name())
.build());
var basicHub = new Hub("basicHub", HubArgs.builder()
.name("hub-basic")
.build());
var linkedVpcSpoke = new Spoke("linkedVpcSpoke", SpokeArgs.builder()
.name("vpc-spoke")
.location("global")
.hub(basicHub.id())
.linkedVpcNetwork(SpokeLinkedVpcNetworkArgs.builder()
.uri(network.selfLink())
.build())
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("producer-spoke")
.location("global")
.description("A sample spoke with a linked router appliance instance")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.linkedProducerVpcNetwork(SpokeLinkedProducerVpcNetworkArgs.builder()
.network(network.name())
.peering(peering.peering())
.excludeExportRanges(
"198.51.100.0/24",
"10.10.0.0/16")
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(linkedVpcSpoke)
.build());
}
}
resources:
network:
type: gcp:compute:Network
properties:
name: net-spoke
autoCreateSubnetworks: false
address:
type: gcp:compute:GlobalAddress
properties:
name: test-address
purpose: VPC_PEERING
addressType: INTERNAL
prefixLength: 16
network: ${network.id}
peering:
type: gcp:servicenetworking:Connection
properties:
network: ${network.id}
service: servicenetworking.googleapis.com
reservedPeeringRanges:
- ${address.name}
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: hub-basic
linkedVpcSpoke:
type: gcp:networkconnectivity:Spoke
name: linked_vpc_spoke
properties:
name: vpc-spoke
location: global
hub: ${basicHub.id}
linkedVpcNetwork:
uri: ${network.selfLink}
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: producer-spoke
location: global
description: A sample spoke with a linked router appliance instance
labels:
label-one: value-one
hub: ${basicHub.id}
linkedProducerVpcNetwork:
network: ${network.name}
peering: ${peering.peering}
excludeExportRanges:
- 198.51.100.0/24
- 10.10.0.0/16
options:
dependsOn:
- ${linkedVpcSpoke}
The linkedProducerVpcNetwork property attaches a service producer network. The network property specifies the VPC name, and the peering property identifies the VPC peering connection created by the managed service. The excludeExportRanges property prevents specific ranges from being advertised. This spoke type requires an existing linked VPC spoke, shown in the dependsOn relationship.
Deploy traffic inspection gateways
Organizations requiring centralized security inspection deploy gateway spokes that process traffic between other spokes, applying firewall rules or deep packet inspection.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const network = new gcp.compute.Network("network", {
name: "net-spoke",
autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
name: "tf-test-subnet_16178",
ipCidrRange: "10.0.0.0/28",
region: "us-central1",
network: network.selfLink,
});
const basicHub = new gcp.networkconnectivity.Hub("basic_hub", {
name: "hub",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
presetTopology: "HYBRID_INSPECTION",
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "gateway",
location: "us-central1",
description: "A sample spoke of type Gateway",
labels: {
"label-one": "value-one",
},
hub: basicHub.id,
gateway: {
ipRangeReservations: [{
ipRange: "10.0.0.0/23",
}],
capacity: "CAPACITY_1_GBPS",
},
group: "gateways",
});
import pulumi
import pulumi_gcp as gcp
network = gcp.compute.Network("network",
name="net-spoke",
auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
name="tf-test-subnet_16178",
ip_cidr_range="10.0.0.0/28",
region="us-central1",
network=network.self_link)
basic_hub = gcp.networkconnectivity.Hub("basic_hub",
name="hub",
description="A sample hub",
labels={
"label-two": "value-one",
},
preset_topology="HYBRID_INSPECTION")
primary = gcp.networkconnectivity.Spoke("primary",
name="gateway",
location="us-central1",
description="A sample spoke of type Gateway",
labels={
"label-one": "value-one",
},
hub=basic_hub.id,
gateway={
"ip_range_reservations": [{
"ip_range": "10.0.0.0/23",
}],
"capacity": "CAPACITY_1_GBPS",
},
group="gateways")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkconnectivity"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
network, err := compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
Name: pulumi.String("net-spoke"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
_, err = compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
Name: pulumi.String("tf-test-subnet_16178"),
IpCidrRange: pulumi.String("10.0.0.0/28"),
Region: pulumi.String("us-central1"),
Network: network.SelfLink,
})
if err != nil {
return err
}
basicHub, err := networkconnectivity.NewHub(ctx, "basic_hub", &networkconnectivity.HubArgs{
Name: pulumi.String("hub"),
Description: pulumi.String("A sample hub"),
Labels: pulumi.StringMap{
"label-two": pulumi.String("value-one"),
},
PresetTopology: pulumi.String("HYBRID_INSPECTION"),
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "primary", &networkconnectivity.SpokeArgs{
Name: pulumi.String("gateway"),
Location: pulumi.String("us-central1"),
Description: pulumi.String("A sample spoke of type Gateway"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Hub: basicHub.ID(),
Gateway: &networkconnectivity.SpokeGatewayArgs{
IpRangeReservations: networkconnectivity.SpokeGatewayIpRangeReservationArray{
&networkconnectivity.SpokeGatewayIpRangeReservationArgs{
IpRange: pulumi.String("10.0.0.0/23"),
},
},
Capacity: pulumi.String("CAPACITY_1_GBPS"),
},
Group: pulumi.String("gateways"),
})
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 network = new Gcp.Compute.Network("network", new()
{
Name = "net-spoke",
AutoCreateSubnetworks = false,
});
var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
{
Name = "tf-test-subnet_16178",
IpCidrRange = "10.0.0.0/28",
Region = "us-central1",
Network = network.SelfLink,
});
var basicHub = new Gcp.NetworkConnectivity.Hub("basic_hub", new()
{
Name = "hub",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
PresetTopology = "HYBRID_INSPECTION",
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "gateway",
Location = "us-central1",
Description = "A sample spoke of type Gateway",
Labels =
{
{ "label-one", "value-one" },
},
Hub = basicHub.Id,
Gateway = new Gcp.NetworkConnectivity.Inputs.SpokeGatewayArgs
{
IpRangeReservations = new[]
{
new Gcp.NetworkConnectivity.Inputs.SpokeGatewayIpRangeReservationArgs
{
IpRange = "10.0.0.0/23",
},
},
Capacity = "CAPACITY_1_GBPS",
},
Group = "gateways",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
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.networkconnectivity.Hub;
import com.pulumi.gcp.networkconnectivity.HubArgs;
import com.pulumi.gcp.networkconnectivity.Spoke;
import com.pulumi.gcp.networkconnectivity.SpokeArgs;
import com.pulumi.gcp.networkconnectivity.inputs.SpokeGatewayArgs;
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 network = new Network("network", NetworkArgs.builder()
.name("net-spoke")
.autoCreateSubnetworks(false)
.build());
var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
.name("tf-test-subnet_16178")
.ipCidrRange("10.0.0.0/28")
.region("us-central1")
.network(network.selfLink())
.build());
var basicHub = new Hub("basicHub", HubArgs.builder()
.name("hub")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.presetTopology("HYBRID_INSPECTION")
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("gateway")
.location("us-central1")
.description("A sample spoke of type Gateway")
.labels(Map.of("label-one", "value-one"))
.hub(basicHub.id())
.gateway(SpokeGatewayArgs.builder()
.ipRangeReservations(SpokeGatewayIpRangeReservationArgs.builder()
.ipRange("10.0.0.0/23")
.build())
.capacity("CAPACITY_1_GBPS")
.build())
.group("gateways")
.build());
}
}
resources:
network:
type: gcp:compute:Network
properties:
name: net-spoke
autoCreateSubnetworks: false
subnetwork:
type: gcp:compute:Subnetwork
properties:
name: tf-test-subnet_16178
ipCidrRange: 10.0.0.0/28
region: us-central1
network: ${network.selfLink}
basicHub:
type: gcp:networkconnectivity:Hub
name: basic_hub
properties:
name: hub
description: A sample hub
labels:
label-two: value-one
presetTopology: HYBRID_INSPECTION
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: gateway
location: us-central1
description: A sample spoke of type Gateway
labels:
label-one: value-one
hub: ${basicHub.id}
gateway:
ipRangeReservations:
- ipRange: 10.0.0.0/23
capacity: CAPACITY_1_GBPS
group: gateways
The gateway property defines an inspection gateway. The ipRangeReservations property allocates IP ranges for gateway processing. The capacity property sets throughput limits (CAPACITY_1_GBPS, CAPACITY_10_GBPS). Gateway spokes require a hub with HYBRID_INSPECTION preset topology and are assigned to the “gateways” group for routing policy application.
Beyond these examples
These snippets focus on specific spoke-level features: VPC network attachment with route filtering, hybrid connectivity through VPN and Interconnect, and traffic inspection via router appliances and gateways. They’re intentionally minimal rather than full network architectures.
The examples reference pre-existing infrastructure such as VPC networks, subnets, Cloud Routers, VPN tunnels, gateways, Interconnect attachments, Compute Engine instances configured for routing, and Network Connectivity Center hubs. They focus on configuring the spoke rather than provisioning the underlying network infrastructure.
To keep things focused, common spoke patterns are omitted, including:
- Hub creation and topology configuration (STAR, MESH, HYBRID_INSPECTION)
- Group membership and auto-accept policies
- IPv6 route advertisement (ALL_IPV6_RANGES)
- Import range filtering beyond ALL_IPV4_RANGES
These omissions are intentional: the goal is to illustrate how each spoke type is wired, not provide drop-in network modules. See the Network Connectivity Spoke resource reference for all available configuration options.
Let's configure GCP Network Connectivity Spokes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
hub, location, name, group, gateway, and linkedProducerVpcNetwork properties are immutable and cannot be changed after spoke creation. Changes to these properties require replacing the resource.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), use the effectiveLabels output property.Linking Resources
You can link five types of resources to a spoke:
- VPC networks - Use
linkedVpcNetwork - Router appliance instances - Use
linkedRouterApplianceInstances - VPN tunnels - Use
linkedVpnTunnels - Interconnect attachments - Use
linkedInterconnectAttachments - Producer VPC networks - Use
linkedProducerVpcNetwork(for service networking)
linkedVpcNetwork spoke connects your own VPC network, while a linkedProducerVpcNetwork spoke connects a VPC from a service producer (like Cloud SQL) via VPC peering. Producer VPC spokes require an existing VPC spoke in the same hub and should use dependsOn to ensure proper creation order.linkedProducerVpcNetwork spoke, you must first create a linkedVpcNetwork spoke in the same hub. Use Pulumi’s dependsOn option to enforce this dependency.Network Routing & Ranges
includeExportRanges and excludeExportRanges to control exported routes. For router appliances, VPN tunnels, and interconnect attachments, use includeImportRanges to control imported routes. You can specify CIDR blocks (e.g., 198.51.100.0/24) or special values like ALL_IPV4_RANGES, ALL_IPV6_RANGES, or ALL_PRIVATE_IPV4_RANGES.siteToSiteDataTransfer boolean enables direct data transfer between sites connected through the spoke (for router appliances, VPN tunnels, and interconnect attachments). When set to true, traffic can flow directly between connected sites without routing through Google Cloud.Advanced Features
group property to associate a spoke with a hub group. For STAR topology hubs, you can create a center group with autoAccept configuration to automatically accept spokes from specified projects.HYBRID_INSPECTION topology hubs. Configure it with capacity (e.g., CAPACITY_1_GBPS) and ipRangeReservations to reserve IP ranges for the gateway.Using a different cloud?
Explore networking guides for other cloud providers: