Configure GCP Cloud Router BGP Peers

The gcp:compute/routerPeer:RouterPeer resource, part of the Pulumi GCP provider, defines BGP peering sessions between Cloud Routers and external peers, controlling route exchange and session parameters. This guide focuses on four capabilities: basic BGP session establishment, BFD failure detection, router appliance integration, and route policy filtering.

BGP peers require existing Cloud Routers with configured interfaces, and may reference VPN tunnels, VM instances, or Network Connectivity Center resources. The examples are intentionally small. Combine them with your own routing infrastructure and network topology.

Establish a basic BGP peering session

Most BGP deployments begin by establishing a peering session between a Cloud Router and an external peer, exchanging routing information to enable dynamic path selection.

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

const peer = new gcp.compute.RouterPeer("peer", {
    name: "my-router-peer",
    router: "my-router",
    region: "us-central1",
    peerAsn: 65513,
    advertisedRoutePriority: 100,
    "interface": "interface-1",
});
import pulumi
import pulumi_gcp as gcp

peer = gcp.compute.RouterPeer("peer",
    name="my-router-peer",
    router="my-router",
    region="us-central1",
    peer_asn=65513,
    advertised_route_priority=100,
    interface="interface-1")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewRouterPeer(ctx, "peer", &compute.RouterPeerArgs{
			Name:                    pulumi.String("my-router-peer"),
			Router:                  pulumi.String("my-router"),
			Region:                  pulumi.String("us-central1"),
			PeerAsn:                 pulumi.Int(65513),
			AdvertisedRoutePriority: pulumi.Int(100),
			Interface:               pulumi.String("interface-1"),
		})
		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 peer = new Gcp.Compute.RouterPeer("peer", new()
    {
        Name = "my-router-peer",
        Router = "my-router",
        Region = "us-central1",
        PeerAsn = 65513,
        AdvertisedRoutePriority = 100,
        Interface = "interface-1",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RouterPeer;
import com.pulumi.gcp.compute.RouterPeerArgs;
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 peer = new RouterPeer("peer", RouterPeerArgs.builder()
            .name("my-router-peer")
            .router("my-router")
            .region("us-central1")
            .peerAsn(65513)
            .advertisedRoutePriority(100)
            .interface_("interface-1")
            .build());

    }
}
resources:
  peer:
    type: gcp:compute:RouterPeer
    properties:
      name: my-router-peer
      router: my-router
      region: us-central1
      peerAsn: 65513
      advertisedRoutePriority: 100
      interface: interface-1

The peerAsn property specifies the Autonomous System Number of the external peer. The advertisedRoutePriority controls route preference when multiple paths exist; lower values win. The interface property binds the peer to a specific router interface, and the router property identifies which Cloud Router hosts this session.

Enable fast failure detection with BFD

Networks that require rapid detection of link failures use Bidirectional Forwarding Detection to identify path issues within seconds rather than minutes.

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

const peer = new gcp.compute.RouterPeer("peer", {
    name: "my-router-peer",
    router: "my-router",
    region: "us-central1",
    peerIpAddress: "169.254.1.2",
    peerAsn: 65513,
    advertisedRoutePriority: 100,
    "interface": "interface-1",
    bfd: {
        minReceiveInterval: 1000,
        minTransmitInterval: 1000,
        multiplier: 5,
        sessionInitializationMode: "ACTIVE",
    },
});
import pulumi
import pulumi_gcp as gcp

peer = gcp.compute.RouterPeer("peer",
    name="my-router-peer",
    router="my-router",
    region="us-central1",
    peer_ip_address="169.254.1.2",
    peer_asn=65513,
    advertised_route_priority=100,
    interface="interface-1",
    bfd={
        "min_receive_interval": 1000,
        "min_transmit_interval": 1000,
        "multiplier": 5,
        "session_initialization_mode": "ACTIVE",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewRouterPeer(ctx, "peer", &compute.RouterPeerArgs{
			Name:                    pulumi.String("my-router-peer"),
			Router:                  pulumi.String("my-router"),
			Region:                  pulumi.String("us-central1"),
			PeerIpAddress:           pulumi.String("169.254.1.2"),
			PeerAsn:                 pulumi.Int(65513),
			AdvertisedRoutePriority: pulumi.Int(100),
			Interface:               pulumi.String("interface-1"),
			Bfd: &compute.RouterPeerBfdArgs{
				MinReceiveInterval:        pulumi.Int(1000),
				MinTransmitInterval:       pulumi.Int(1000),
				Multiplier:                pulumi.Int(5),
				SessionInitializationMode: pulumi.String("ACTIVE"),
			},
		})
		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 peer = new Gcp.Compute.RouterPeer("peer", new()
    {
        Name = "my-router-peer",
        Router = "my-router",
        Region = "us-central1",
        PeerIpAddress = "169.254.1.2",
        PeerAsn = 65513,
        AdvertisedRoutePriority = 100,
        Interface = "interface-1",
        Bfd = new Gcp.Compute.Inputs.RouterPeerBfdArgs
        {
            MinReceiveInterval = 1000,
            MinTransmitInterval = 1000,
            Multiplier = 5,
            SessionInitializationMode = "ACTIVE",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RouterPeer;
import com.pulumi.gcp.compute.RouterPeerArgs;
import com.pulumi.gcp.compute.inputs.RouterPeerBfdArgs;
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 peer = new RouterPeer("peer", RouterPeerArgs.builder()
            .name("my-router-peer")
            .router("my-router")
            .region("us-central1")
            .peerIpAddress("169.254.1.2")
            .peerAsn(65513)
            .advertisedRoutePriority(100)
            .interface_("interface-1")
            .bfd(RouterPeerBfdArgs.builder()
                .minReceiveInterval(1000)
                .minTransmitInterval(1000)
                .multiplier(5)
                .sessionInitializationMode("ACTIVE")
                .build())
            .build());

    }
}
resources:
  peer:
    type: gcp:compute:RouterPeer
    properties:
      name: my-router-peer
      router: my-router
      region: us-central1
      peerIpAddress: 169.254.1.2
      peerAsn: 65513
      advertisedRoutePriority: 100
      interface: interface-1
      bfd:
        minReceiveInterval: 1000
        minTransmitInterval: 1000
        multiplier: 5
        sessionInitializationMode: ACTIVE

The bfd block configures failure detection intervals and behavior. The minReceiveInterval and minTransmitInterval properties set how frequently BFD packets are exchanged (in milliseconds). The multiplier determines how many missed packets trigger failure detection. The sessionInitializationMode controls whether this peer actively initiates BFD or waits passively.

Peer with third-party network appliances

Hybrid cloud architectures often route traffic through virtual appliances like firewalls or SD-WAN devices that participate in BGP routing.

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

const network = new gcp.compute.Network("network", {
    name: "my-router-net",
    autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
    name: "my-router-sub",
    network: network.selfLink,
    ipCidrRange: "10.0.0.0/16",
    region: "us-central1",
});
const addrIntf = new gcp.compute.Address("addr_intf", {
    name: "my-router-addr-intf",
    region: subnetwork.region,
    subnetwork: subnetwork.id,
    addressType: "INTERNAL",
});
const addrIntfRedundant = new gcp.compute.Address("addr_intf_redundant", {
    name: "my-router-addr-intf-red",
    region: subnetwork.region,
    subnetwork: subnetwork.id,
    addressType: "INTERNAL",
});
const addrPeer = new gcp.compute.Address("addr_peer", {
    name: "my-router-addr-peer",
    region: subnetwork.region,
    subnetwork: subnetwork.id,
    addressType: "INTERNAL",
});
const instance = new gcp.compute.Instance("instance", {
    name: "router-appliance",
    zone: "us-central1-a",
    machineType: "e2-medium",
    canIpForward: true,
    bootDisk: {
        initializeParams: {
            image: "debian-cloud/debian-11",
        },
    },
    networkInterfaces: [{
        networkIp: addrPeer.address,
        subnetwork: subnetwork.selfLink,
    }],
});
const hub = new gcp.networkconnectivity.Hub("hub", {name: "my-router-hub"});
const spoke = new gcp.networkconnectivity.Spoke("spoke", {
    name: "my-router-spoke",
    location: subnetwork.region,
    hub: hub.id,
    linkedRouterApplianceInstances: {
        instances: [{
            virtualMachine: instance.selfLink,
            ipAddress: addrPeer.address,
        }],
        siteToSiteDataTransfer: false,
    },
});
const router = new gcp.compute.Router("router", {
    name: "my-router-router",
    region: subnetwork.region,
    network: network.selfLink,
    bgp: {
        asn: 64514,
    },
});
const interfaceRedundant = new gcp.compute.RouterInterface("interface_redundant", {
    name: "my-router-intf-red",
    region: router.region,
    router: router.name,
    subnetwork: subnetwork.selfLink,
    privateIpAddress: addrIntfRedundant.address,
});
const _interface = new gcp.compute.RouterInterface("interface", {
    name: "my-router-intf",
    region: router.region,
    router: router.name,
    subnetwork: subnetwork.selfLink,
    privateIpAddress: addrIntf.address,
    redundantInterface: interfaceRedundant.name,
});
const peer = new gcp.compute.RouterPeer("peer", {
    name: "my-router-peer",
    router: router.name,
    region: router.region,
    "interface": _interface.name,
    routerApplianceInstance: instance.selfLink,
    peerAsn: 65513,
    peerIpAddress: addrPeer.address,
});
import pulumi
import pulumi_gcp as gcp

network = gcp.compute.Network("network",
    name="my-router-net",
    auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
    name="my-router-sub",
    network=network.self_link,
    ip_cidr_range="10.0.0.0/16",
    region="us-central1")
addr_intf = gcp.compute.Address("addr_intf",
    name="my-router-addr-intf",
    region=subnetwork.region,
    subnetwork=subnetwork.id,
    address_type="INTERNAL")
addr_intf_redundant = gcp.compute.Address("addr_intf_redundant",
    name="my-router-addr-intf-red",
    region=subnetwork.region,
    subnetwork=subnetwork.id,
    address_type="INTERNAL")
addr_peer = gcp.compute.Address("addr_peer",
    name="my-router-addr-peer",
    region=subnetwork.region,
    subnetwork=subnetwork.id,
    address_type="INTERNAL")
instance = gcp.compute.Instance("instance",
    name="router-appliance",
    zone="us-central1-a",
    machine_type="e2-medium",
    can_ip_forward=True,
    boot_disk={
        "initialize_params": {
            "image": "debian-cloud/debian-11",
        },
    },
    network_interfaces=[{
        "network_ip": addr_peer.address,
        "subnetwork": subnetwork.self_link,
    }])
hub = gcp.networkconnectivity.Hub("hub", name="my-router-hub")
spoke = gcp.networkconnectivity.Spoke("spoke",
    name="my-router-spoke",
    location=subnetwork.region,
    hub=hub.id,
    linked_router_appliance_instances={
        "instances": [{
            "virtual_machine": instance.self_link,
            "ip_address": addr_peer.address,
        }],
        "site_to_site_data_transfer": False,
    })
router = gcp.compute.Router("router",
    name="my-router-router",
    region=subnetwork.region,
    network=network.self_link,
    bgp={
        "asn": 64514,
    })
interface_redundant = gcp.compute.RouterInterface("interface_redundant",
    name="my-router-intf-red",
    region=router.region,
    router=router.name,
    subnetwork=subnetwork.self_link,
    private_ip_address=addr_intf_redundant.address)
interface = gcp.compute.RouterInterface("interface",
    name="my-router-intf",
    region=router.region,
    router=router.name,
    subnetwork=subnetwork.self_link,
    private_ip_address=addr_intf.address,
    redundant_interface=interface_redundant.name)
peer = gcp.compute.RouterPeer("peer",
    name="my-router-peer",
    router=router.name,
    region=router.region,
    interface=interface.name,
    router_appliance_instance=instance.self_link,
    peer_asn=65513,
    peer_ip_address=addr_peer.address)
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("my-router-net"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
subnetwork, err := compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
Name: pulumi.String("my-router-sub"),
Network: network.SelfLink,
IpCidrRange: pulumi.String("10.0.0.0/16"),
Region: pulumi.String("us-central1"),
})
if err != nil {
return err
}
addrIntf, err := compute.NewAddress(ctx, "addr_intf", &compute.AddressArgs{
Name: pulumi.String("my-router-addr-intf"),
Region: subnetwork.Region,
Subnetwork: subnetwork.ID(),
AddressType: pulumi.String("INTERNAL"),
})
if err != nil {
return err
}
addrIntfRedundant, err := compute.NewAddress(ctx, "addr_intf_redundant", &compute.AddressArgs{
Name: pulumi.String("my-router-addr-intf-red"),
Region: subnetwork.Region,
Subnetwork: subnetwork.ID(),
AddressType: pulumi.String("INTERNAL"),
})
if err != nil {
return err
}
addrPeer, err := compute.NewAddress(ctx, "addr_peer", &compute.AddressArgs{
Name: pulumi.String("my-router-addr-peer"),
Region: subnetwork.Region,
Subnetwork: subnetwork.ID(),
AddressType: pulumi.String("INTERNAL"),
})
if err != nil {
return err
}
instance, err := compute.NewInstance(ctx, "instance", &compute.InstanceArgs{
Name: pulumi.String("router-appliance"),
Zone: pulumi.String("us-central1-a"),
MachineType: pulumi.String("e2-medium"),
CanIpForward: pulumi.Bool(true),
BootDisk: &compute.InstanceBootDiskArgs{
InitializeParams: &compute.InstanceBootDiskInitializeParamsArgs{
Image: pulumi.String("debian-cloud/debian-11"),
},
},
NetworkInterfaces: compute.InstanceNetworkInterfaceArray{
&compute.InstanceNetworkInterfaceArgs{
NetworkIp: addrPeer.Address,
Subnetwork: subnetwork.SelfLink,
},
},
})
if err != nil {
return err
}
hub, err := networkconnectivity.NewHub(ctx, "hub", &networkconnectivity.HubArgs{
Name: pulumi.String("my-router-hub"),
})
if err != nil {
return err
}
_, err = networkconnectivity.NewSpoke(ctx, "spoke", &networkconnectivity.SpokeArgs{
Name: pulumi.String("my-router-spoke"),
Location: subnetwork.Region,
Hub: hub.ID(),
LinkedRouterApplianceInstances: &networkconnectivity.SpokeLinkedRouterApplianceInstancesArgs{
Instances: networkconnectivity.SpokeLinkedRouterApplianceInstancesInstanceArray{
&networkconnectivity.SpokeLinkedRouterApplianceInstancesInstanceArgs{
VirtualMachine: instance.SelfLink,
IpAddress: addrPeer.Address,
},
},
SiteToSiteDataTransfer: pulumi.Bool(false),
},
})
if err != nil {
return err
}
router, err := compute.NewRouter(ctx, "router", &compute.RouterArgs{
Name: pulumi.String("my-router-router"),
Region: subnetwork.Region,
Network: network.SelfLink,
Bgp: &compute.RouterBgpArgs{
Asn: pulumi.Int(64514),
},
})
if err != nil {
return err
}
interfaceRedundant, err := compute.NewRouterInterface(ctx, "interface_redundant", &compute.RouterInterfaceArgs{
Name: pulumi.String("my-router-intf-red"),
Region: router.Region,
Router: router.Name,
Subnetwork: subnetwork.SelfLink,
PrivateIpAddress: addrIntfRedundant.Address,
})
if err != nil {
return err
}
interface, err := compute.NewRouterInterface(ctx, "interface", &compute.RouterInterfaceArgs{
Name: pulumi.String("my-router-intf"),
Region: router.Region,
Router: router.Name,
Subnetwork: subnetwork.SelfLink,
PrivateIpAddress: addrIntf.Address,
RedundantInterface: interfaceRedundant.Name,
})
if err != nil {
return err
}
_, err = compute.NewRouterPeer(ctx, "peer", &compute.RouterPeerArgs{
Name: pulumi.String("my-router-peer"),
Router: router.Name,
Region: router.Region,
Interface: interface.Name,
RouterApplianceInstance: instance.SelfLink,
PeerAsn: pulumi.Int(65513),
PeerIpAddress: addrPeer.Address,
})
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 = "my-router-net",
        AutoCreateSubnetworks = false,
    });

    var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
    {
        Name = "my-router-sub",
        Network = network.SelfLink,
        IpCidrRange = "10.0.0.0/16",
        Region = "us-central1",
    });

    var addrIntf = new Gcp.Compute.Address("addr_intf", new()
    {
        Name = "my-router-addr-intf",
        Region = subnetwork.Region,
        Subnetwork = subnetwork.Id,
        AddressType = "INTERNAL",
    });

    var addrIntfRedundant = new Gcp.Compute.Address("addr_intf_redundant", new()
    {
        Name = "my-router-addr-intf-red",
        Region = subnetwork.Region,
        Subnetwork = subnetwork.Id,
        AddressType = "INTERNAL",
    });

    var addrPeer = new Gcp.Compute.Address("addr_peer", new()
    {
        Name = "my-router-addr-peer",
        Region = subnetwork.Region,
        Subnetwork = subnetwork.Id,
        AddressType = "INTERNAL",
    });

    var instance = new Gcp.Compute.Instance("instance", new()
    {
        Name = "router-appliance",
        Zone = "us-central1-a",
        MachineType = "e2-medium",
        CanIpForward = true,
        BootDisk = new Gcp.Compute.Inputs.InstanceBootDiskArgs
        {
            InitializeParams = new Gcp.Compute.Inputs.InstanceBootDiskInitializeParamsArgs
            {
                Image = "debian-cloud/debian-11",
            },
        },
        NetworkInterfaces = new[]
        {
            new Gcp.Compute.Inputs.InstanceNetworkInterfaceArgs
            {
                NetworkIp = addrPeer.IPAddress,
                Subnetwork = subnetwork.SelfLink,
            },
        },
    });

    var hub = new Gcp.NetworkConnectivity.Hub("hub", new()
    {
        Name = "my-router-hub",
    });

    var spoke = new Gcp.NetworkConnectivity.Spoke("spoke", new()
    {
        Name = "my-router-spoke",
        Location = subnetwork.Region,
        Hub = hub.Id,
        LinkedRouterApplianceInstances = new Gcp.NetworkConnectivity.Inputs.SpokeLinkedRouterApplianceInstancesArgs
        {
            Instances = new[]
            {
                new Gcp.NetworkConnectivity.Inputs.SpokeLinkedRouterApplianceInstancesInstanceArgs
                {
                    VirtualMachine = instance.SelfLink,
                    IpAddress = addrPeer.IPAddress,
                },
            },
            SiteToSiteDataTransfer = false,
        },
    });

    var router = new Gcp.Compute.Router("router", new()
    {
        Name = "my-router-router",
        Region = subnetwork.Region,
        Network = network.SelfLink,
        Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
        {
            Asn = 64514,
        },
    });

    var interfaceRedundant = new Gcp.Compute.RouterInterface("interface_redundant", new()
    {
        Name = "my-router-intf-red",
        Region = router.Region,
        Router = router.Name,
        Subnetwork = subnetwork.SelfLink,
        PrivateIpAddress = addrIntfRedundant.IPAddress,
    });

    var @interface = new Gcp.Compute.RouterInterface("interface", new()
    {
        Name = "my-router-intf",
        Region = router.Region,
        Router = router.Name,
        Subnetwork = subnetwork.SelfLink,
        PrivateIpAddress = addrIntf.IPAddress,
        RedundantInterface = interfaceRedundant.Name,
    });

    var peer = new Gcp.Compute.RouterPeer("peer", new()
    {
        Name = "my-router-peer",
        Router = router.Name,
        Region = router.Region,
        Interface = @interface.Name,
        RouterApplianceInstance = instance.SelfLink,
        PeerAsn = 65513,
        PeerIpAddress = addrPeer.IPAddress,
    });

});
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.Address;
import com.pulumi.gcp.compute.AddressArgs;
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 com.pulumi.gcp.compute.Router;
import com.pulumi.gcp.compute.RouterArgs;
import com.pulumi.gcp.compute.inputs.RouterBgpArgs;
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 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("my-router-net")
            .autoCreateSubnetworks(false)
            .build());

        var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
            .name("my-router-sub")
            .network(network.selfLink())
            .ipCidrRange("10.0.0.0/16")
            .region("us-central1")
            .build());

        var addrIntf = new Address("addrIntf", AddressArgs.builder()
            .name("my-router-addr-intf")
            .region(subnetwork.region())
            .subnetwork(subnetwork.id())
            .addressType("INTERNAL")
            .build());

        var addrIntfRedundant = new Address("addrIntfRedundant", AddressArgs.builder()
            .name("my-router-addr-intf-red")
            .region(subnetwork.region())
            .subnetwork(subnetwork.id())
            .addressType("INTERNAL")
            .build());

        var addrPeer = new Address("addrPeer", AddressArgs.builder()
            .name("my-router-addr-peer")
            .region(subnetwork.region())
            .subnetwork(subnetwork.id())
            .addressType("INTERNAL")
            .build());

        var instance = new Instance("instance", InstanceArgs.builder()
            .name("router-appliance")
            .zone("us-central1-a")
            .machineType("e2-medium")
            .canIpForward(true)
            .bootDisk(InstanceBootDiskArgs.builder()
                .initializeParams(InstanceBootDiskInitializeParamsArgs.builder()
                    .image("debian-cloud/debian-11")
                    .build())
                .build())
            .networkInterfaces(InstanceNetworkInterfaceArgs.builder()
                .networkIp(addrPeer.address())
                .subnetwork(subnetwork.selfLink())
                .build())
            .build());

        var hub = new Hub("hub", HubArgs.builder()
            .name("my-router-hub")
            .build());

        var spoke = new Spoke("spoke", SpokeArgs.builder()
            .name("my-router-spoke")
            .location(subnetwork.region())
            .hub(hub.id())
            .linkedRouterApplianceInstances(SpokeLinkedRouterApplianceInstancesArgs.builder()
                .instances(SpokeLinkedRouterApplianceInstancesInstanceArgs.builder()
                    .virtualMachine(instance.selfLink())
                    .ipAddress(addrPeer.address())
                    .build())
                .siteToSiteDataTransfer(false)
                .build())
            .build());

        var router = new Router("router", RouterArgs.builder()
            .name("my-router-router")
            .region(subnetwork.region())
            .network(network.selfLink())
            .bgp(RouterBgpArgs.builder()
                .asn(64514)
                .build())
            .build());

        var interfaceRedundant = new RouterInterface("interfaceRedundant", RouterInterfaceArgs.builder()
            .name("my-router-intf-red")
            .region(router.region())
            .router(router.name())
            .subnetwork(subnetwork.selfLink())
            .privateIpAddress(addrIntfRedundant.address())
            .build());

        var interface_ = new RouterInterface("interface", RouterInterfaceArgs.builder()
            .name("my-router-intf")
            .region(router.region())
            .router(router.name())
            .subnetwork(subnetwork.selfLink())
            .privateIpAddress(addrIntf.address())
            .redundantInterface(interfaceRedundant.name())
            .build());

        var peer = new RouterPeer("peer", RouterPeerArgs.builder()
            .name("my-router-peer")
            .router(router.name())
            .region(router.region())
            .interface_(interface_.name())
            .routerApplianceInstance(instance.selfLink())
            .peerAsn(65513)
            .peerIpAddress(addrPeer.address())
            .build());

    }
}
resources:
  network:
    type: gcp:compute:Network
    properties:
      name: my-router-net
      autoCreateSubnetworks: false
  subnetwork:
    type: gcp:compute:Subnetwork
    properties:
      name: my-router-sub
      network: ${network.selfLink}
      ipCidrRange: 10.0.0.0/16
      region: us-central1
  addrIntf:
    type: gcp:compute:Address
    name: addr_intf
    properties:
      name: my-router-addr-intf
      region: ${subnetwork.region}
      subnetwork: ${subnetwork.id}
      addressType: INTERNAL
  addrIntfRedundant:
    type: gcp:compute:Address
    name: addr_intf_redundant
    properties:
      name: my-router-addr-intf-red
      region: ${subnetwork.region}
      subnetwork: ${subnetwork.id}
      addressType: INTERNAL
  addrPeer:
    type: gcp:compute:Address
    name: addr_peer
    properties:
      name: my-router-addr-peer
      region: ${subnetwork.region}
      subnetwork: ${subnetwork.id}
      addressType: INTERNAL
  instance:
    type: gcp:compute:Instance
    properties:
      name: router-appliance
      zone: us-central1-a
      machineType: e2-medium
      canIpForward: true
      bootDisk:
        initializeParams:
          image: debian-cloud/debian-11
      networkInterfaces:
        - networkIp: ${addrPeer.address}
          subnetwork: ${subnetwork.selfLink}
  hub:
    type: gcp:networkconnectivity:Hub
    properties:
      name: my-router-hub
  spoke:
    type: gcp:networkconnectivity:Spoke
    properties:
      name: my-router-spoke
      location: ${subnetwork.region}
      hub: ${hub.id}
      linkedRouterApplianceInstances:
        instances:
          - virtualMachine: ${instance.selfLink}
            ipAddress: ${addrPeer.address}
        siteToSiteDataTransfer: false
  router:
    type: gcp:compute:Router
    properties:
      name: my-router-router
      region: ${subnetwork.region}
      network: ${network.selfLink}
      bgp:
        asn: 64514
  interfaceRedundant:
    type: gcp:compute:RouterInterface
    name: interface_redundant
    properties:
      name: my-router-intf-red
      region: ${router.region}
      router: ${router.name}
      subnetwork: ${subnetwork.selfLink}
      privateIpAddress: ${addrIntfRedundant.address}
  interface:
    type: gcp:compute:RouterInterface
    properties:
      name: my-router-intf
      region: ${router.region}
      router: ${router.name}
      subnetwork: ${subnetwork.selfLink}
      privateIpAddress: ${addrIntf.address}
      redundantInterface: ${interfaceRedundant.name}
  peer:
    type: gcp:compute:RouterPeer
    properties:
      name: my-router-peer
      router: ${router.name}
      region: ${router.region}
      interface: ${interface.name}
      routerApplianceInstance: ${instance.selfLink}
      peerAsn: 65513
      peerIpAddress: ${addrPeer.address}

The routerApplianceInstance property points to a VM instance that acts as the BGP peer. This example creates a Network Connectivity Center spoke to register the appliance, then establishes BGP peering between the Cloud Router and the VM’s IP address. The linkedRouterApplianceInstances block in the spoke configuration identifies which VM participates in routing.

Secure BGP sessions with MD5 authentication

Production BGP sessions typically require authentication to prevent route injection attacks and ensure only authorized peers can establish sessions.

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

const foobar = new gcp.compute.RouterPeer("foobar", {
    name: "%s-peer",
    router: foobarGoogleComputeRouter.name,
    region: foobarGoogleComputeRouter.region,
    peerAsn: 65515,
    advertisedRoutePriority: 100,
    "interface": foobarGoogleComputeRouterInterface.name,
    peerIpAddress: "169.254.3.2",
    md5AuthenticationKey: {
        name: "%s-peer-key",
        key: "%s-peer-key-value",
    },
});
import pulumi
import pulumi_gcp as gcp

foobar = gcp.compute.RouterPeer("foobar",
    name="%s-peer",
    router=foobar_google_compute_router["name"],
    region=foobar_google_compute_router["region"],
    peer_asn=65515,
    advertised_route_priority=100,
    interface=foobar_google_compute_router_interface["name"],
    peer_ip_address="169.254.3.2",
    md5_authentication_key={
        "name": "%s-peer-key",
        "key": "%s-peer-key-value",
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewRouterPeer(ctx, "foobar", &compute.RouterPeerArgs{
			Name:                    pulumi.String("%s-peer"),
			Router:                  pulumi.Any(foobarGoogleComputeRouter.Name),
			Region:                  pulumi.Any(foobarGoogleComputeRouter.Region),
			PeerAsn:                 pulumi.Int(65515),
			AdvertisedRoutePriority: pulumi.Int(100),
			Interface:               pulumi.Any(foobarGoogleComputeRouterInterface.Name),
			PeerIpAddress:           pulumi.String("169.254.3.2"),
			Md5AuthenticationKey: &compute.RouterPeerMd5AuthenticationKeyArgs{
				Name: pulumi.String("%s-peer-key"),
				Key:  pulumi.String("%s-peer-key-value"),
			},
		})
		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 foobar = new Gcp.Compute.RouterPeer("foobar", new()
    {
        Name = "%s-peer",
        Router = foobarGoogleComputeRouter.Name,
        Region = foobarGoogleComputeRouter.Region,
        PeerAsn = 65515,
        AdvertisedRoutePriority = 100,
        Interface = foobarGoogleComputeRouterInterface.Name,
        PeerIpAddress = "169.254.3.2",
        Md5AuthenticationKey = new Gcp.Compute.Inputs.RouterPeerMd5AuthenticationKeyArgs
        {
            Name = "%s-peer-key",
            Key = "%s-peer-key-value",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RouterPeer;
import com.pulumi.gcp.compute.RouterPeerArgs;
import com.pulumi.gcp.compute.inputs.RouterPeerMd5AuthenticationKeyArgs;
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 foobar = new RouterPeer("foobar", RouterPeerArgs.builder()
            .name("%s-peer")
            .router(foobarGoogleComputeRouter.name())
            .region(foobarGoogleComputeRouter.region())
            .peerAsn(65515)
            .advertisedRoutePriority(100)
            .interface_(foobarGoogleComputeRouterInterface.name())
            .peerIpAddress("169.254.3.2")
            .md5AuthenticationKey(RouterPeerMd5AuthenticationKeyArgs.builder()
                .name("%s-peer-key")
                .key("%s-peer-key-value")
                .build())
            .build());

    }
}
resources:
  foobar:
    type: gcp:compute:RouterPeer
    properties:
      name: '%s-peer'
      router: ${foobarGoogleComputeRouter.name}
      region: ${foobarGoogleComputeRouter.region}
      peerAsn: 65515
      advertisedRoutePriority: 100
      interface: ${foobarGoogleComputeRouterInterface.name}
      peerIpAddress: 169.254.3.2
      md5AuthenticationKey:
        name: '%s-peer-key'
        key: '%s-peer-key-value'

The md5AuthenticationKey block configures shared-secret authentication for the BGP session. Both the name and key properties must match on both sides of the peering relationship. This prevents unauthorized routers from establishing sessions and injecting routes.

Control route advertisement with import and export policies

Complex routing topologies require fine-grained control over which routes are learned from peers and which local routes are advertised outbound.

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

const network = new gcp.compute.Network("network", {
    name: "my-router-net",
    autoCreateSubnetworks: false,
});
const subnetwork = new gcp.compute.Subnetwork("subnetwork", {
    name: "my-router-subnet",
    network: network.selfLink,
    ipCidrRange: "10.0.0.0/16",
    region: "us-central1",
});
const address = new gcp.compute.Address("address", {
    name: "my-router",
    region: subnetwork.region,
});
const vpnGateway = new gcp.compute.HaVpnGateway("vpn_gateway", {
    name: "my-router-gateway",
    network: network.selfLink,
    region: subnetwork.region,
});
const externalGateway = new gcp.compute.ExternalVpnGateway("external_gateway", {
    name: "my-router-external-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: "my-router",
    region: subnetwork.region,
    network: network.selfLink,
    bgp: {
        asn: 64514,
    },
});
const vpnTunnel = new gcp.compute.VPNTunnel("vpn_tunnel", {
    name: "my-router",
    region: subnetwork.region,
    vpnGateway: vpnGateway.id,
    peerExternalGateway: externalGateway.id,
    peerExternalGatewayInterface: 0,
    sharedSecret: "unguessable",
    router: router.name,
    vpnGatewayInterface: 0,
});
const routerInterface = new gcp.compute.RouterInterface("router_interface", {
    name: "my-router",
    router: router.name,
    region: router.region,
    vpnTunnel: vpnTunnel.name,
});
const rp_export = new gcp.compute.RouterRoutePolicy("rp-export", {
    name: "my-router-rp-export",
    router: router.name,
    region: router.region,
    type: "ROUTE_POLICY_TYPE_EXPORT",
    terms: [{
        priority: 2,
        match: {
            expression: "destination == '10.0.0.0/12'",
            title: "export_expression",
            description: "acceptance expression for export",
        },
        actions: [{
            expression: "accept()",
        }],
    }],
}, {
    dependsOn: [routerInterface],
});
const rp_import = new gcp.compute.RouterRoutePolicy("rp-import", {
    name: "my-router-rp-import",
    router: router.name,
    region: router.region,
    type: "ROUTE_POLICY_TYPE_IMPORT",
    terms: [{
        priority: 1,
        match: {
            expression: "destination == '10.0.0.0/12'",
            title: "import_expression",
            description: "acceptance expression for import",
        },
        actions: [{
            expression: "accept()",
        }],
    }],
}, {
    dependsOn: [
        routerInterface,
        rp_export,
    ],
});
const routerPeer = new gcp.compute.RouterPeer("router_peer", {
    name: "my-router-peer",
    router: router.name,
    region: router.region,
    peerAsn: 65515,
    advertisedRoutePriority: 100,
    "interface": routerInterface.name,
    md5AuthenticationKey: {
        name: "my-router-peer-key",
        key: "my-router-peer-key-value",
    },
    importPolicies: [rp_import.name],
    exportPolicies: [rp_export.name],
}, {
    dependsOn: [
        rp_export,
        rp_import,
        routerInterface,
    ],
});
import pulumi
import pulumi_gcp as gcp

network = gcp.compute.Network("network",
    name="my-router-net",
    auto_create_subnetworks=False)
subnetwork = gcp.compute.Subnetwork("subnetwork",
    name="my-router-subnet",
    network=network.self_link,
    ip_cidr_range="10.0.0.0/16",
    region="us-central1")
address = gcp.compute.Address("address",
    name="my-router",
    region=subnetwork.region)
vpn_gateway = gcp.compute.HaVpnGateway("vpn_gateway",
    name="my-router-gateway",
    network=network.self_link,
    region=subnetwork.region)
external_gateway = gcp.compute.ExternalVpnGateway("external_gateway",
    name="my-router-external-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="my-router",
    region=subnetwork.region,
    network=network.self_link,
    bgp={
        "asn": 64514,
    })
vpn_tunnel = gcp.compute.VPNTunnel("vpn_tunnel",
    name="my-router",
    region=subnetwork.region,
    vpn_gateway=vpn_gateway.id,
    peer_external_gateway=external_gateway.id,
    peer_external_gateway_interface=0,
    shared_secret="unguessable",
    router=router.name,
    vpn_gateway_interface=0)
router_interface = gcp.compute.RouterInterface("router_interface",
    name="my-router",
    router=router.name,
    region=router.region,
    vpn_tunnel=vpn_tunnel.name)
rp_export = gcp.compute.RouterRoutePolicy("rp-export",
    name="my-router-rp-export",
    router=router.name,
    region=router.region,
    type="ROUTE_POLICY_TYPE_EXPORT",
    terms=[{
        "priority": 2,
        "match": {
            "expression": "destination == '10.0.0.0/12'",
            "title": "export_expression",
            "description": "acceptance expression for export",
        },
        "actions": [{
            "expression": "accept()",
        }],
    }],
    opts = pulumi.ResourceOptions(depends_on=[router_interface]))
rp_import = gcp.compute.RouterRoutePolicy("rp-import",
    name="my-router-rp-import",
    router=router.name,
    region=router.region,
    type="ROUTE_POLICY_TYPE_IMPORT",
    terms=[{
        "priority": 1,
        "match": {
            "expression": "destination == '10.0.0.0/12'",
            "title": "import_expression",
            "description": "acceptance expression for import",
        },
        "actions": [{
            "expression": "accept()",
        }],
    }],
    opts = pulumi.ResourceOptions(depends_on=[
            router_interface,
            rp_export,
        ]))
router_peer = gcp.compute.RouterPeer("router_peer",
    name="my-router-peer",
    router=router.name,
    region=router.region,
    peer_asn=65515,
    advertised_route_priority=100,
    interface=router_interface.name,
    md5_authentication_key={
        "name": "my-router-peer-key",
        "key": "my-router-peer-key-value",
    },
    import_policies=[rp_import.name],
    export_policies=[rp_export.name],
    opts = pulumi.ResourceOptions(depends_on=[
            rp_export,
            rp_import,
            router_interface,
        ]))
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"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("my-router-net"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		subnetwork, err := compute.NewSubnetwork(ctx, "subnetwork", &compute.SubnetworkArgs{
			Name:        pulumi.String("my-router-subnet"),
			Network:     network.SelfLink,
			IpCidrRange: pulumi.String("10.0.0.0/16"),
			Region:      pulumi.String("us-central1"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewAddress(ctx, "address", &compute.AddressArgs{
			Name:   pulumi.String("my-router"),
			Region: subnetwork.Region,
		})
		if err != nil {
			return err
		}
		vpnGateway, err := compute.NewHaVpnGateway(ctx, "vpn_gateway", &compute.HaVpnGatewayArgs{
			Name:    pulumi.String("my-router-gateway"),
			Network: network.SelfLink,
			Region:  subnetwork.Region,
		})
		if err != nil {
			return err
		}
		externalGateway, err := compute.NewExternalVpnGateway(ctx, "external_gateway", &compute.ExternalVpnGatewayArgs{
			Name:           pulumi.String("my-router-external-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("my-router"),
			Region:  subnetwork.Region,
			Network: network.SelfLink,
			Bgp: &compute.RouterBgpArgs{
				Asn: pulumi.Int(64514),
			},
		})
		if err != nil {
			return err
		}
		vpnTunnel, err := compute.NewVPNTunnel(ctx, "vpn_tunnel", &compute.VPNTunnelArgs{
			Name:                         pulumi.String("my-router"),
			Region:                       subnetwork.Region,
			VpnGateway:                   vpnGateway.ID(),
			PeerExternalGateway:          externalGateway.ID(),
			PeerExternalGatewayInterface: pulumi.Int(0),
			SharedSecret:                 pulumi.String("unguessable"),
			Router:                       router.Name,
			VpnGatewayInterface:          pulumi.Int(0),
		})
		if err != nil {
			return err
		}
		routerInterface, err := compute.NewRouterInterface(ctx, "router_interface", &compute.RouterInterfaceArgs{
			Name:      pulumi.String("my-router"),
			Router:    router.Name,
			Region:    router.Region,
			VpnTunnel: vpnTunnel.Name,
		})
		if err != nil {
			return err
		}
		rp_export, err := compute.NewRouterRoutePolicy(ctx, "rp-export", &compute.RouterRoutePolicyArgs{
			Name:   pulumi.String("my-router-rp-export"),
			Router: router.Name,
			Region: router.Region,
			Type:   pulumi.String("ROUTE_POLICY_TYPE_EXPORT"),
			Terms: compute.RouterRoutePolicyTermArray{
				&compute.RouterRoutePolicyTermArgs{
					Priority: pulumi.Int(2),
					Match: &compute.RouterRoutePolicyTermMatchArgs{
						Expression:  pulumi.String("destination == '10.0.0.0/12'"),
						Title:       pulumi.String("export_expression"),
						Description: pulumi.String("acceptance expression for export"),
					},
					Actions: compute.RouterRoutePolicyTermActionArray{
						&compute.RouterRoutePolicyTermActionArgs{
							Expression: pulumi.String("accept()"),
						},
					},
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			routerInterface,
		}))
		if err != nil {
			return err
		}
		rp_import, err := compute.NewRouterRoutePolicy(ctx, "rp-import", &compute.RouterRoutePolicyArgs{
			Name:   pulumi.String("my-router-rp-import"),
			Router: router.Name,
			Region: router.Region,
			Type:   pulumi.String("ROUTE_POLICY_TYPE_IMPORT"),
			Terms: compute.RouterRoutePolicyTermArray{
				&compute.RouterRoutePolicyTermArgs{
					Priority: pulumi.Int(1),
					Match: &compute.RouterRoutePolicyTermMatchArgs{
						Expression:  pulumi.String("destination == '10.0.0.0/12'"),
						Title:       pulumi.String("import_expression"),
						Description: pulumi.String("acceptance expression for import"),
					},
					Actions: compute.RouterRoutePolicyTermActionArray{
						&compute.RouterRoutePolicyTermActionArgs{
							Expression: pulumi.String("accept()"),
						},
					},
				},
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			routerInterface,
			rp_export,
		}))
		if err != nil {
			return err
		}
		_, err = compute.NewRouterPeer(ctx, "router_peer", &compute.RouterPeerArgs{
			Name:                    pulumi.String("my-router-peer"),
			Router:                  router.Name,
			Region:                  router.Region,
			PeerAsn:                 pulumi.Int(65515),
			AdvertisedRoutePriority: pulumi.Int(100),
			Interface:               routerInterface.Name,
			Md5AuthenticationKey: &compute.RouterPeerMd5AuthenticationKeyArgs{
				Name: pulumi.String("my-router-peer-key"),
				Key:  pulumi.String("my-router-peer-key-value"),
			},
			ImportPolicies: pulumi.StringArray{
				rp_import.Name,
			},
			ExportPolicies: pulumi.StringArray{
				rp_export.Name,
			},
		}, pulumi.DependsOn([]pulumi.Resource{
			rp_export,
			rp_import,
			routerInterface,
		}))
		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 = "my-router-net",
        AutoCreateSubnetworks = false,
    });

    var subnetwork = new Gcp.Compute.Subnetwork("subnetwork", new()
    {
        Name = "my-router-subnet",
        Network = network.SelfLink,
        IpCidrRange = "10.0.0.0/16",
        Region = "us-central1",
    });

    var address = new Gcp.Compute.Address("address", new()
    {
        Name = "my-router",
        Region = subnetwork.Region,
    });

    var vpnGateway = new Gcp.Compute.HaVpnGateway("vpn_gateway", new()
    {
        Name = "my-router-gateway",
        Network = network.SelfLink,
        Region = subnetwork.Region,
    });

    var externalGateway = new Gcp.Compute.ExternalVpnGateway("external_gateway", new()
    {
        Name = "my-router-external-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 = "my-router",
        Region = subnetwork.Region,
        Network = network.SelfLink,
        Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
        {
            Asn = 64514,
        },
    });

    var vpnTunnel = new Gcp.Compute.VPNTunnel("vpn_tunnel", new()
    {
        Name = "my-router",
        Region = subnetwork.Region,
        VpnGateway = vpnGateway.Id,
        PeerExternalGateway = externalGateway.Id,
        PeerExternalGatewayInterface = 0,
        SharedSecret = "unguessable",
        Router = router.Name,
        VpnGatewayInterface = 0,
    });

    var routerInterface = new Gcp.Compute.RouterInterface("router_interface", new()
    {
        Name = "my-router",
        Router = router.Name,
        Region = router.Region,
        VpnTunnel = vpnTunnel.Name,
    });

    var rp_export = new Gcp.Compute.RouterRoutePolicy("rp-export", new()
    {
        Name = "my-router-rp-export",
        Router = router.Name,
        Region = router.Region,
        Type = "ROUTE_POLICY_TYPE_EXPORT",
        Terms = new[]
        {
            new Gcp.Compute.Inputs.RouterRoutePolicyTermArgs
            {
                Priority = 2,
                Match = new Gcp.Compute.Inputs.RouterRoutePolicyTermMatchArgs
                {
                    Expression = "destination == '10.0.0.0/12'",
                    Title = "export_expression",
                    Description = "acceptance expression for export",
                },
                Actions = new[]
                {
                    new Gcp.Compute.Inputs.RouterRoutePolicyTermActionArgs
                    {
                        Expression = "accept()",
                    },
                },
            },
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            routerInterface,
        },
    });

    var rp_import = new Gcp.Compute.RouterRoutePolicy("rp-import", new()
    {
        Name = "my-router-rp-import",
        Router = router.Name,
        Region = router.Region,
        Type = "ROUTE_POLICY_TYPE_IMPORT",
        Terms = new[]
        {
            new Gcp.Compute.Inputs.RouterRoutePolicyTermArgs
            {
                Priority = 1,
                Match = new Gcp.Compute.Inputs.RouterRoutePolicyTermMatchArgs
                {
                    Expression = "destination == '10.0.0.0/12'",
                    Title = "import_expression",
                    Description = "acceptance expression for import",
                },
                Actions = new[]
                {
                    new Gcp.Compute.Inputs.RouterRoutePolicyTermActionArgs
                    {
                        Expression = "accept()",
                    },
                },
            },
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            routerInterface,
            rp_export,
        },
    });

    var routerPeer = new Gcp.Compute.RouterPeer("router_peer", new()
    {
        Name = "my-router-peer",
        Router = router.Name,
        Region = router.Region,
        PeerAsn = 65515,
        AdvertisedRoutePriority = 100,
        Interface = routerInterface.Name,
        Md5AuthenticationKey = new Gcp.Compute.Inputs.RouterPeerMd5AuthenticationKeyArgs
        {
            Name = "my-router-peer-key",
            Key = "my-router-peer-key-value",
        },
        ImportPolicies = new[]
        {
            rp_import.Name,
        },
        ExportPolicies = new[]
        {
            rp_export.Name,
        },
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            rp_export,
            rp_import,
            routerInterface,
        },
    });

});
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.Address;
import com.pulumi.gcp.compute.AddressArgs;
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.RouterRoutePolicy;
import com.pulumi.gcp.compute.RouterRoutePolicyArgs;
import com.pulumi.gcp.compute.inputs.RouterRoutePolicyTermArgs;
import com.pulumi.gcp.compute.inputs.RouterRoutePolicyTermMatchArgs;
import com.pulumi.gcp.compute.RouterPeer;
import com.pulumi.gcp.compute.RouterPeerArgs;
import com.pulumi.gcp.compute.inputs.RouterPeerMd5AuthenticationKeyArgs;
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("my-router-net")
            .autoCreateSubnetworks(false)
            .build());

        var subnetwork = new Subnetwork("subnetwork", SubnetworkArgs.builder()
            .name("my-router-subnet")
            .network(network.selfLink())
            .ipCidrRange("10.0.0.0/16")
            .region("us-central1")
            .build());

        var address = new Address("address", AddressArgs.builder()
            .name("my-router")
            .region(subnetwork.region())
            .build());

        var vpnGateway = new HaVpnGateway("vpnGateway", HaVpnGatewayArgs.builder()
            .name("my-router-gateway")
            .network(network.selfLink())
            .region(subnetwork.region())
            .build());

        var externalGateway = new ExternalVpnGateway("externalGateway", ExternalVpnGatewayArgs.builder()
            .name("my-router-external-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("my-router")
            .region(subnetwork.region())
            .network(network.selfLink())
            .bgp(RouterBgpArgs.builder()
                .asn(64514)
                .build())
            .build());

        var vpnTunnel = new VPNTunnel("vpnTunnel", VPNTunnelArgs.builder()
            .name("my-router")
            .region(subnetwork.region())
            .vpnGateway(vpnGateway.id())
            .peerExternalGateway(externalGateway.id())
            .peerExternalGatewayInterface(0)
            .sharedSecret("unguessable")
            .router(router.name())
            .vpnGatewayInterface(0)
            .build());

        var routerInterface = new RouterInterface("routerInterface", RouterInterfaceArgs.builder()
            .name("my-router")
            .router(router.name())
            .region(router.region())
            .vpnTunnel(vpnTunnel.name())
            .build());

        var rp_export = new RouterRoutePolicy("rp-export", RouterRoutePolicyArgs.builder()
            .name("my-router-rp-export")
            .router(router.name())
            .region(router.region())
            .type("ROUTE_POLICY_TYPE_EXPORT")
            .terms(RouterRoutePolicyTermArgs.builder()
                .priority(2)
                .match(RouterRoutePolicyTermMatchArgs.builder()
                    .expression("destination == '10.0.0.0/12'")
                    .title("export_expression")
                    .description("acceptance expression for export")
                    .build())
                .actions(RouterRoutePolicyTermActionArgs.builder()
                    .expression("accept()")
                    .build())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(routerInterface)
                .build());

        var rp_import = new RouterRoutePolicy("rp-import", RouterRoutePolicyArgs.builder()
            .name("my-router-rp-import")
            .router(router.name())
            .region(router.region())
            .type("ROUTE_POLICY_TYPE_IMPORT")
            .terms(RouterRoutePolicyTermArgs.builder()
                .priority(1)
                .match(RouterRoutePolicyTermMatchArgs.builder()
                    .expression("destination == '10.0.0.0/12'")
                    .title("import_expression")
                    .description("acceptance expression for import")
                    .build())
                .actions(RouterRoutePolicyTermActionArgs.builder()
                    .expression("accept()")
                    .build())
                .build())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    routerInterface,
                    rp_export)
                .build());

        var routerPeer = new RouterPeer("routerPeer", RouterPeerArgs.builder()
            .name("my-router-peer")
            .router(router.name())
            .region(router.region())
            .peerAsn(65515)
            .advertisedRoutePriority(100)
            .interface_(routerInterface.name())
            .md5AuthenticationKey(RouterPeerMd5AuthenticationKeyArgs.builder()
                .name("my-router-peer-key")
                .key("my-router-peer-key-value")
                .build())
            .importPolicies(rp_import.name())
            .exportPolicies(rp_export.name())
            .build(), CustomResourceOptions.builder()
                .dependsOn(                
                    rp_export,
                    rp_import,
                    routerInterface)
                .build());

    }
}
resources:
  network:
    type: gcp:compute:Network
    properties:
      name: my-router-net
      autoCreateSubnetworks: false
  subnetwork:
    type: gcp:compute:Subnetwork
    properties:
      name: my-router-subnet
      network: ${network.selfLink}
      ipCidrRange: 10.0.0.0/16
      region: us-central1
  address:
    type: gcp:compute:Address
    properties:
      name: my-router
      region: ${subnetwork.region}
  vpnGateway:
    type: gcp:compute:HaVpnGateway
    name: vpn_gateway
    properties:
      name: my-router-gateway
      network: ${network.selfLink}
      region: ${subnetwork.region}
  externalGateway:
    type: gcp:compute:ExternalVpnGateway
    name: external_gateway
    properties:
      name: my-router-external-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: my-router
      region: ${subnetwork.region}
      network: ${network.selfLink}
      bgp:
        asn: 64514
  vpnTunnel:
    type: gcp:compute:VPNTunnel
    name: vpn_tunnel
    properties:
      name: my-router
      region: ${subnetwork.region}
      vpnGateway: ${vpnGateway.id}
      peerExternalGateway: ${externalGateway.id}
      peerExternalGatewayInterface: 0
      sharedSecret: unguessable
      router: ${router.name}
      vpnGatewayInterface: 0
  routerInterface:
    type: gcp:compute:RouterInterface
    name: router_interface
    properties:
      name: my-router
      router: ${router.name}
      region: ${router.region}
      vpnTunnel: ${vpnTunnel.name}
  rp-export:
    type: gcp:compute:RouterRoutePolicy
    properties:
      name: my-router-rp-export
      router: ${router.name}
      region: ${router.region}
      type: ROUTE_POLICY_TYPE_EXPORT
      terms:
        - priority: 2
          match:
            expression: destination == '10.0.0.0/12'
            title: export_expression
            description: acceptance expression for export
          actions:
            - expression: accept()
    options:
      dependsOn:
        - ${routerInterface}
  rp-import:
    type: gcp:compute:RouterRoutePolicy
    properties:
      name: my-router-rp-import
      router: ${router.name}
      region: ${router.region}
      type: ROUTE_POLICY_TYPE_IMPORT
      terms:
        - priority: 1
          match:
            expression: destination == '10.0.0.0/12'
            title: import_expression
            description: acceptance expression for import
          actions:
            - expression: accept()
    options:
      dependsOn:
        - ${routerInterface}
        - ${["rp-export"]}
  routerPeer:
    type: gcp:compute:RouterPeer
    name: router_peer
    properties:
      name: my-router-peer
      router: ${router.name}
      region: ${router.region}
      peerAsn: 65515
      advertisedRoutePriority: 100
      interface: ${routerInterface.name}
      md5AuthenticationKey:
        name: my-router-peer-key
        key: my-router-peer-key-value
      importPolicies:
        - ${["rp-import"].name}
      exportPolicies:
        - ${["rp-export"].name}
    options:
      dependsOn:
        - ${["rp-export"]}
        - ${["rp-import"]}
        - ${routerInterface}

The importPolicies and exportPolicies properties reference RouterRoutePolicy resources that filter routes based on expressions. Each policy contains terms with match conditions (using CEL expressions like “destination == ‘10.0.0.0/12’”) and actions (accept or reject). Import policies control which routes are learned from the peer; export policies control which local routes are advertised. The dependsOn relationships ensure policies exist before the peer references them.

Beyond these examples

These snippets focus on specific BGP peer features: basic peering and ASN configuration, failure detection with BFD, and router appliance integration and route policy filtering. They’re intentionally minimal rather than full routing deployments.

The examples may reference pre-existing infrastructure such as Cloud Routers with configured interfaces, VPC networks and subnets, and VM instances for router appliance scenarios. They focus on configuring the BGP peer rather than provisioning the entire routing stack.

To keep things focused, common BGP peer patterns are omitted, including:

  • Custom route advertisement (advertiseMode, advertisedGroups, advertisedIpRanges)
  • IPv6 peering (enableIpv6, ipv6NexthopAddress)
  • Custom learned route priorities and ranges
  • Session enable/disable controls

These omissions are intentional: the goal is to illustrate how each BGP peer feature is wired, not provide drop-in routing modules. See the RouterPeer resource reference for all available configuration options.

Let's configure GCP Cloud Router BGP Peers

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Immutability
What properties can't I change after creating a BGP peer?
The interface, name, router, region, and project properties are immutable. Changing any of these forces resource replacement.
What are the naming requirements for a BGP peer?
The name must be 1-63 characters long and match the regex [a-z][-a-z0-9]*[a-z0-9]?. It must start with a lowercase letter, end with a letter or digit, and contain only lowercase letters, digits, and dashes.
Route Advertisement & Priorities
How do I set route priority to 0?
To set advertisedRoutePriority to 0, you must also set zeroAdvertisedRoutePriority: true. Similarly, to set customLearnedRoutePriority to 0, set zeroCustomLearnedRoutePriority: true.
What's the default priority for custom learned routes?
If you don’t provide a value for customLearnedRoutePriority, Google Cloud assigns a priority of 100. You can choose any value from 0 to 65335.
When can I use advertisedGroups or advertisedIpRanges?
These fields can only be set when advertiseMode is CUSTOM. They override the router’s default advertisement settings and are advertised in addition to any specified prefixes.
IPv6 & Addressing
What are the valid IPv6 address ranges for next hop addresses?
Both ipv6NexthopAddress and peerIpv6NexthopAddress must be in the range 2600:2d00:0:2::/64 or 2600:2d00:0:3::/64. If not specified, Google Cloud automatically assigns unused addresses from these ranges.
Advanced Features
How do I configure import and export policies?
Use importPolicies and exportPolicies arrays with names of existing gcp.compute.RouterRoutePolicy resources. Policies must have the correct type (ROUTE_POLICY_TYPE_IMPORT or ROUTE_POLICY_TYPE_EXPORT) and are evaluated in the order specified.
How do I enable BFD for BGP peering?
Configure the bfd property with minReceiveInterval, minTransmitInterval, multiplier, and sessionInitializationMode.
How do I enable MD5 authentication?
Set the md5AuthenticationKey property with a name and key value.
What's a router appliance instance?
A routerApplianceInstance is a VM instance used as a third-party router appliance (such as a Next Gen Firewall or Virtual Router). The VM must be located in zones within the same region as the Cloud Router.
Management & Lifecycle
How do I disable a BGP peer without deleting it?
Set enable: false. This terminates the active session and removes all associated routing information. Set it back to true to re-establish the connection.
Can I modify all BGP peers?
No. Peers with managementType set to MANAGED_BY_ATTACHMENT are managed by Cloud Interconnect and cannot be manually updated. Only MANAGED_BY_USER peers can be modified.

Using a different cloud?

Explore networking guides for other cloud providers: