The gcp:networkconnectivity/spoke:Spoke resource, part of the Pulumi GCP provider, defines a spoke in Network Connectivity Center that connects networks to a central hub for transitive routing. This guide focuses on three capabilities: VPC network attachment with route filtering, router appliance and VPN tunnel connectivity, and gateway spokes for traffic inspection.
Spokes attach to Network Connectivity Center hubs and reference existing infrastructure such as VPC networks, Compute Engine instances, VPN tunnels, or interconnect attachments. The examples are intentionally small. Combine them with your own hub topology and network infrastructure.
Connect a VPC network with route filtering
Most Network Connectivity Center deployments begin by attaching VPC networks to a hub, enabling transitive connectivity between spokes.
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 includeExportRanges property specifies which IP ranges this spoke advertises to other spokes, while excludeExportRanges removes specific subnets from advertisement. This controls which routes propagate through the hub, preventing unwanted connectivity or routing conflicts.
Route traffic through network virtual appliances
Organizations that need centralized security inspection deploy router appliance instances as spokes, directing traffic through virtual appliances before reaching other networks.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const network = new gcp.compute.Network("network", {
name: "tf-test-network_11171",
autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
name: "tf-test-subnet_40472",
ipCidrRange: "10.0.0.0/28",
region: "us-central1",
network: network.selfLink,
});
const instance = new gcp.compute.Instance("instance", {
name: "tf-test-instance_44339",
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_34599",
description: "A sample hub",
labels: {
"label-two": "value-one",
},
});
const primary = new gcp.networkconnectivity.Spoke("primary", {
name: "tf-test-name_79513",
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_11171",
auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
name="tf-test-subnet_40472",
ip_cidr_range="10.0.0.0/28",
region="us-central1",
network=network.self_link)
instance = gcp.compute.Instance("instance",
name="tf-test-instance_44339",
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_34599",
description="A sample hub",
labels={
"label-two": "value-one",
})
primary = gcp.networkconnectivity.Spoke("primary",
name="tf-test-name_79513",
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_11171"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
subnetwork, err := compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
Name: pulumi.String("tf-test-subnet_40472"),
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_44339"),
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_34599"),
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_79513"),
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_11171",
AutoCreateSubnetworks = false,
});
var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
{
Name = "tf-test-subnet_40472",
IpCidrRange = "10.0.0.0/28",
Region = "us-central1",
Network = network.SelfLink,
});
var instance = new Gcp.Compute.Instance("instance", new()
{
Name = "tf-test-instance_44339",
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_34599",
Description = "A sample hub",
Labels =
{
{ "label-two", "value-one" },
},
});
var primary = new Gcp.NetworkConnectivity.Spoke("primary", new()
{
Name = "tf-test-name_79513",
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_11171")
.autoCreateSubnetworks(false)
.build());
var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
.name("tf-test-subnet_40472")
.ipCidrRange("10.0.0.0/28")
.region("us-central1")
.network(network.selfLink())
.build());
var instance = new Instance("instance", InstanceArgs.builder()
.name("tf-test-instance_44339")
.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_34599")
.description("A sample hub")
.labels(Map.of("label-two", "value-one"))
.build());
var primary = new Spoke("primary", SpokeArgs.builder()
.name("tf-test-name_79513")
.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_11171
autoCreateSubnetworks: false
subnetwork:
type: gcp:compute:Subnetwork
properties:
name: tf-test-subnet_40472
ipCidrRange: 10.0.0.0/28
region: us-central1
network: ${network.selfLink}
instance:
type: gcp:compute:Instance
properties:
name: tf-test-instance_44339
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_34599
description: A sample hub
labels:
label-two: value-one
primary:
type: gcp:networkconnectivity:Spoke
properties:
name: tf-test-name_79513
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 references Compute Engine instances configured for IP forwarding. The virtualMachine property points to the instance, and ipAddress specifies the internal IP that receives traffic. Setting siteToSiteDataTransfer to true enables data transfer between spokes through this appliance. The includeImportRanges property controls which routes the appliance advertises.
Connect on-premises networks via VPN tunnels
Hybrid cloud architectures use VPN tunnels to connect on-premises data centers, with Network Connectivity Center providing transitive routing between on-premises and cloud networks.
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 references existing VPN tunnel resources by their self-links. Multiple tunnels provide redundancy. The siteToSiteDataTransfer property enables traffic flow between this spoke and others, while includeImportRanges determines which routes are imported from the on-premises network. This configuration assumes BGP peering is already established on the Cloud Router.
Connect via dedicated or partner interconnect
Enterprise workloads requiring high bandwidth and low latency use Cloud Interconnect attachments, which Network Connectivity Center integrates for transitive routing.
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 references InterconnectAttachment resources. Like VPN spokes, siteToSiteDataTransfer enables transitive connectivity, and includeImportRanges controls route advertisement. Interconnect attachments provide higher bandwidth and lower latency than VPN tunnels, making them suitable for production workloads with strict performance requirements.
Deploy a gateway spoke for traffic inspection
Hybrid inspection topologies use gateway spokes to apply specialized processing to traffic flowing between networks.
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_49547",
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_49547",
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_49547"),
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_49547",
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_49547")
.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_49547
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 a spoke that processes traffic rather than connecting a network. The ipRangeReservations property allocates IP ranges for the gateway’s internal use, and capacity sets the throughput limit. Gateway spokes require a hub with presetTopology set to HYBRID_INSPECTION and must be assigned to the “gateways” group. Traffic between other spokes flows through gateway spokes for inspection or processing.
Beyond these examples
These snippets focus on specific spoke-level features: VPC network attachment with route filtering, router appliance, VPN, and interconnect connectivity, and gateway spokes for traffic inspection. They’re intentionally minimal rather than full network architectures.
The examples reference pre-existing infrastructure such as VPC networks, subnets, Cloud Routers, Compute Engine instances (for router appliances), VPN gateways, tunnels, BGP peering, interconnect attachments, 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:
- Producer VPC network spokes (service networking)
- Group-based spoke organization and auto-accept policies
- IPv6 route advertisement (ALL_IPV6_RANGES)
- Spoke lifecycle management (state transitions)
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
Spoke Configuration & Types
linkedVpcNetwork), router appliance instances (linkedRouterApplianceInstances), VPN tunnels (linkedVpnTunnels), interconnect attachments (linkedInterconnectAttachments), producer VPC networks (linkedProducerVpcNetwork), or create a gateway spoke (gateway).linkedVpcNetwork) connects your own VPC network to the hub. A producer VPC spoke (linkedProducerVpcNetwork) connects a service producer’s VPC network (like Cloud SQL or other managed services) that’s peered via Service Networking.STAR topology for standard hub-and-spoke configurations and HYBRID_INSPECTION topology for gateway-based traffic inspection.Immutability & Updates
hub, location, name, group, project, gateway, and linkedProducerVpcNetwork. Changing any of these requires replacing the spoke resource.dependsOn to ensure the VPC spoke is created first.IP Range Management
includeExportRanges to specify which CIDR ranges to export and excludeExportRanges to exclude specific ranges. You can use special values like ALL_IPV6_RANGES or ALL_PRIVATE_IPV4_RANGES.ALL_IPV4_RANGES is a special value that includes all IPv4 address ranges for import, commonly used with router appliances, VPN tunnels, and interconnect attachments.includeExportRanges to ["ALL_IPV6_RANGES", "ALL_PRIVATE_IPV4_RANGES"] in your linkedVpcNetwork configuration.includeExportRanges (used with VPC spokes) controls which ranges your VPC advertises to the hub. includeImportRanges (used with router appliances, VPN tunnels, and interconnects) controls which ranges are imported from those resources.Labels & Metadata
labels field is non-authoritative and only manages labels defined in your configuration. To see all labels (including those set by other clients or GCP services), use the effectiveLabels output property.Advanced Configuration
siteToSiteDataTransfer enables direct data transfer between sites connected through the spoke, available for router appliances, VPN tunnels, and interconnect attachments.gateway property with ipRangeReservations (IP ranges for the gateway) and capacity (e.g., CAPACITY_1_GBPS). Gateway spokes require a hub with HYBRID_INSPECTION topology.Using a different cloud?
Explore networking guides for other cloud providers: