Configure GCP Interconnect Attachments

The gcp:compute/interconnectAttachment:InterconnectAttachment resource, part of the Pulumi GCP provider, defines a VLAN attachment that connects Cloud Interconnect circuits to VPC networks via Cloud Router. This guide focuses on three capabilities: partner attachments with edge availability domains, IPsec encryption for secure traffic, and dual-stack IPv4/IPv6 addressing.

Interconnect attachments require a Cloud Router in the same region and reference VPC networks that must exist separately. The examples are intentionally small. Combine them with your own VPC infrastructure and routing configuration.

Create a partner attachment with basic configuration

Most Cloud Interconnect deployments begin with a PARTNER attachment that connects your on-premises network to Google Cloud through a service provider.

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

const foobarNetwork = new gcp.compute.Network("foobar", {
    name: "network-1",
    autoCreateSubnetworks: false,
});
const foobar = new gcp.compute.Router("foobar", {
    name: "router-1",
    network: foobarNetwork.name,
    bgp: {
        asn: 16550,
    },
});
const onPrem = new gcp.compute.InterconnectAttachment("on_prem", {
    name: "on-prem-attachment",
    edgeAvailabilityDomain: "AVAILABILITY_DOMAIN_1",
    type: "PARTNER",
    router: foobar.id,
    mtu: "1500",
    labels: {
        mykey: "myvalue",
    },
});
import pulumi
import pulumi_gcp as gcp

foobar_network = gcp.compute.Network("foobar",
    name="network-1",
    auto_create_subnetworks=False)
foobar = gcp.compute.Router("foobar",
    name="router-1",
    network=foobar_network.name,
    bgp={
        "asn": 16550,
    })
on_prem = gcp.compute.InterconnectAttachment("on_prem",
    name="on-prem-attachment",
    edge_availability_domain="AVAILABILITY_DOMAIN_1",
    type="PARTNER",
    router=foobar.id,
    mtu="1500",
    labels={
        "mykey": "myvalue",
    })
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 {
		foobarNetwork, err := compute.NewNetwork(ctx, "foobar", &compute.NetworkArgs{
			Name:                  pulumi.String("network-1"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		foobar, err := compute.NewRouter(ctx, "foobar", &compute.RouterArgs{
			Name:    pulumi.String("router-1"),
			Network: foobarNetwork.Name,
			Bgp: &compute.RouterBgpArgs{
				Asn: pulumi.Int(16550),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewInterconnectAttachment(ctx, "on_prem", &compute.InterconnectAttachmentArgs{
			Name:                   pulumi.String("on-prem-attachment"),
			EdgeAvailabilityDomain: pulumi.String("AVAILABILITY_DOMAIN_1"),
			Type:                   pulumi.String("PARTNER"),
			Router:                 foobar.ID(),
			Mtu:                    pulumi.String("1500"),
			Labels: pulumi.StringMap{
				"mykey": pulumi.String("myvalue"),
			},
		})
		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 foobarNetwork = new Gcp.Compute.Network("foobar", new()
    {
        Name = "network-1",
        AutoCreateSubnetworks = false,
    });

    var foobar = new Gcp.Compute.Router("foobar", new()
    {
        Name = "router-1",
        Network = foobarNetwork.Name,
        Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
        {
            Asn = 16550,
        },
    });

    var onPrem = new Gcp.Compute.InterconnectAttachment("on_prem", new()
    {
        Name = "on-prem-attachment",
        EdgeAvailabilityDomain = "AVAILABILITY_DOMAIN_1",
        Type = "PARTNER",
        Router = foobar.Id,
        Mtu = "1500",
        Labels = 
        {
            { "mykey", "myvalue" },
        },
    });

});
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.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 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 foobarNetwork = new Network("foobarNetwork", NetworkArgs.builder()
            .name("network-1")
            .autoCreateSubnetworks(false)
            .build());

        var foobar = new Router("foobar", RouterArgs.builder()
            .name("router-1")
            .network(foobarNetwork.name())
            .bgp(RouterBgpArgs.builder()
                .asn(16550)
                .build())
            .build());

        var onPrem = new InterconnectAttachment("onPrem", InterconnectAttachmentArgs.builder()
            .name("on-prem-attachment")
            .edgeAvailabilityDomain("AVAILABILITY_DOMAIN_1")
            .type("PARTNER")
            .router(foobar.id())
            .mtu("1500")
            .labels(Map.of("mykey", "myvalue"))
            .build());

    }
}
resources:
  onPrem:
    type: gcp:compute:InterconnectAttachment
    name: on_prem
    properties:
      name: on-prem-attachment
      edgeAvailabilityDomain: AVAILABILITY_DOMAIN_1
      type: PARTNER
      router: ${foobar.id}
      mtu: 1500
      labels:
        mykey: myvalue
  foobar:
    type: gcp:compute:Router
    properties:
      name: router-1
      network: ${foobarNetwork.name}
      bgp:
        asn: 16550
  foobarNetwork:
    type: gcp:compute:Network
    name: foobar
    properties:
      name: network-1
      autoCreateSubnetworks: false

The type property specifies PARTNER, meaning a service provider manages the physical connection. The edgeAvailabilityDomain property determines which Google availability zone hosts the attachment; for redundancy, configure a pair of attachments with one per domain. The router property links the attachment to a Cloud Router for BGP-based dynamic routing, and mtu sets the maximum packet size (1500 bytes in this case).

Encrypt traffic with IPsec over Interconnect

Organizations with strict security requirements can encrypt Interconnect traffic using IPsec, which requires reserved internal IP addresses.

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

const network = new gcp.compute.Network("network", {
    name: "test-network",
    autoCreateSubnetworks: false,
});
const address = new gcp.compute.Address("address", {
    name: "test-address",
    addressType: "INTERNAL",
    purpose: "IPSEC_INTERCONNECT",
    address: "192.168.1.0",
    prefixLength: 29,
    network: network.selfLink,
});
const router = new gcp.compute.Router("router", {
    name: "test-router",
    network: network.name,
    encryptedInterconnectRouter: true,
    bgp: {
        asn: 16550,
    },
});
const ipsec_encrypted_interconnect_attachment = new gcp.compute.InterconnectAttachment("ipsec-encrypted-interconnect-attachment", {
    name: "test-interconnect-attachment",
    edgeAvailabilityDomain: "AVAILABILITY_DOMAIN_1",
    type: "PARTNER",
    router: router.id,
    encryption: "IPSEC",
    ipsecInternalAddresses: [address.selfLink],
});
import pulumi
import pulumi_gcp as gcp

network = gcp.compute.Network("network",
    name="test-network",
    auto_create_subnetworks=False)
address = gcp.compute.Address("address",
    name="test-address",
    address_type="INTERNAL",
    purpose="IPSEC_INTERCONNECT",
    address="192.168.1.0",
    prefix_length=29,
    network=network.self_link)
router = gcp.compute.Router("router",
    name="test-router",
    network=network.name,
    encrypted_interconnect_router=True,
    bgp={
        "asn": 16550,
    })
ipsec_encrypted_interconnect_attachment = gcp.compute.InterconnectAttachment("ipsec-encrypted-interconnect-attachment",
    name="test-interconnect-attachment",
    edge_availability_domain="AVAILABILITY_DOMAIN_1",
    type="PARTNER",
    router=router.id,
    encryption="IPSEC",
    ipsec_internal_addresses=[address.self_link])
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("test-network"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		address, err := compute.NewAddress(ctx, "address", &compute.AddressArgs{
			Name:         pulumi.String("test-address"),
			AddressType:  pulumi.String("INTERNAL"),
			Purpose:      pulumi.String("IPSEC_INTERCONNECT"),
			Address:      pulumi.String("192.168.1.0"),
			PrefixLength: pulumi.Int(29),
			Network:      network.SelfLink,
		})
		if err != nil {
			return err
		}
		router, err := compute.NewRouter(ctx, "router", &compute.RouterArgs{
			Name:                        pulumi.String("test-router"),
			Network:                     network.Name,
			EncryptedInterconnectRouter: pulumi.Bool(true),
			Bgp: &compute.RouterBgpArgs{
				Asn: pulumi.Int(16550),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewInterconnectAttachment(ctx, "ipsec-encrypted-interconnect-attachment", &compute.InterconnectAttachmentArgs{
			Name:                   pulumi.String("test-interconnect-attachment"),
			EdgeAvailabilityDomain: pulumi.String("AVAILABILITY_DOMAIN_1"),
			Type:                   pulumi.String("PARTNER"),
			Router:                 router.ID(),
			Encryption:             pulumi.String("IPSEC"),
			IpsecInternalAddresses: pulumi.StringArray{
				address.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 = "test-network",
        AutoCreateSubnetworks = false,
    });

    var address = new Gcp.Compute.Address("address", new()
    {
        Name = "test-address",
        AddressType = "INTERNAL",
        Purpose = "IPSEC_INTERCONNECT",
        IPAddress = "192.168.1.0",
        PrefixLength = 29,
        Network = network.SelfLink,
    });

    var router = new Gcp.Compute.Router("router", new()
    {
        Name = "test-router",
        Network = network.Name,
        EncryptedInterconnectRouter = true,
        Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
        {
            Asn = 16550,
        },
    });

    var ipsec_encrypted_interconnect_attachment = new Gcp.Compute.InterconnectAttachment("ipsec-encrypted-interconnect-attachment", new()
    {
        Name = "test-interconnect-attachment",
        EdgeAvailabilityDomain = "AVAILABILITY_DOMAIN_1",
        Type = "PARTNER",
        Router = router.Id,
        Encryption = "IPSEC",
        IpsecInternalAddresses = new[]
        {
            address.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.compute.Address;
import com.pulumi.gcp.compute.AddressArgs;
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 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("test-network")
            .autoCreateSubnetworks(false)
            .build());

        var address = new Address("address", AddressArgs.builder()
            .name("test-address")
            .addressType("INTERNAL")
            .purpose("IPSEC_INTERCONNECT")
            .address("192.168.1.0")
            .prefixLength(29)
            .network(network.selfLink())
            .build());

        var router = new Router("router", RouterArgs.builder()
            .name("test-router")
            .network(network.name())
            .encryptedInterconnectRouter(true)
            .bgp(RouterBgpArgs.builder()
                .asn(16550)
                .build())
            .build());

        var ipsec_encrypted_interconnect_attachment = new InterconnectAttachment("ipsec-encrypted-interconnect-attachment", InterconnectAttachmentArgs.builder()
            .name("test-interconnect-attachment")
            .edgeAvailabilityDomain("AVAILABILITY_DOMAIN_1")
            .type("PARTNER")
            .router(router.id())
            .encryption("IPSEC")
            .ipsecInternalAddresses(address.selfLink())
            .build());

    }
}
resources:
  ipsec-encrypted-interconnect-attachment:
    type: gcp:compute:InterconnectAttachment
    properties:
      name: test-interconnect-attachment
      edgeAvailabilityDomain: AVAILABILITY_DOMAIN_1
      type: PARTNER
      router: ${router.id}
      encryption: IPSEC
      ipsecInternalAddresses:
        - ${address.selfLink}
  address:
    type: gcp:compute:Address
    properties:
      name: test-address
      addressType: INTERNAL
      purpose: IPSEC_INTERCONNECT
      address: 192.168.1.0
      prefixLength: 29
      network: ${network.selfLink}
  router:
    type: gcp:compute:Router
    properties:
      name: test-router
      network: ${network.name}
      encryptedInterconnectRouter: true
      bgp:
        asn: 16550
  network:
    type: gcp:compute:Network
    properties:
      name: test-network
      autoCreateSubnetworks: false

Setting encryption to IPSEC ensures all traffic traverses an IPsec tunnel. The ipsecInternalAddresses property references a reserved RFC 1918 address range (created via compute.Address with purpose IPSEC_INTERCONNECT) that provides IP addresses for HA VPN gateways built over the attachment. The Cloud Router must have encryptedInterconnectRouter set to true to support encrypted attachments.

Configure dual-stack IPv4 and IPv6 addressing

Attachments can support both IPv4 and IPv6 traffic by specifying custom IP ranges for both the Cloud Router and customer router interfaces.

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

const foobarNetwork = new gcp.compute.Network("foobar", {
    name: "test-network",
    autoCreateSubnetworks: false,
});
const foobar = new gcp.compute.Router("foobar", {
    name: "test-router",
    network: foobarNetwork.name,
    bgp: {
        asn: 16550,
    },
});
const custom_ranges_interconnect_attachment = new gcp.compute.InterconnectAttachment("custom-ranges-interconnect-attachment", {
    name: "test-custom-ranges-interconnect-attachment",
    edgeAvailabilityDomain: "AVAILABILITY_DOMAIN_1",
    type: "PARTNER",
    router: foobar.id,
    mtu: "1500",
    stackType: "IPV4_IPV6",
    labels: {
        mykey: "myvalue",
    },
    candidateCloudRouterIpAddress: "192.169.0.1/29",
    candidateCustomerRouterIpAddress: "192.169.0.2/29",
    candidateCloudRouterIpv6Address: "748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125",
    candidateCustomerRouterIpv6Address: "748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125",
});
import pulumi
import pulumi_gcp as gcp

foobar_network = gcp.compute.Network("foobar",
    name="test-network",
    auto_create_subnetworks=False)
foobar = gcp.compute.Router("foobar",
    name="test-router",
    network=foobar_network.name,
    bgp={
        "asn": 16550,
    })
custom_ranges_interconnect_attachment = gcp.compute.InterconnectAttachment("custom-ranges-interconnect-attachment",
    name="test-custom-ranges-interconnect-attachment",
    edge_availability_domain="AVAILABILITY_DOMAIN_1",
    type="PARTNER",
    router=foobar.id,
    mtu="1500",
    stack_type="IPV4_IPV6",
    labels={
        "mykey": "myvalue",
    },
    candidate_cloud_router_ip_address="192.169.0.1/29",
    candidate_customer_router_ip_address="192.169.0.2/29",
    candidate_cloud_router_ipv6_address="748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125",
    candidate_customer_router_ipv6_address="748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125")
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 {
		foobarNetwork, err := compute.NewNetwork(ctx, "foobar", &compute.NetworkArgs{
			Name:                  pulumi.String("test-network"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		foobar, err := compute.NewRouter(ctx, "foobar", &compute.RouterArgs{
			Name:    pulumi.String("test-router"),
			Network: foobarNetwork.Name,
			Bgp: &compute.RouterBgpArgs{
				Asn: pulumi.Int(16550),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewInterconnectAttachment(ctx, "custom-ranges-interconnect-attachment", &compute.InterconnectAttachmentArgs{
			Name:                   pulumi.String("test-custom-ranges-interconnect-attachment"),
			EdgeAvailabilityDomain: pulumi.String("AVAILABILITY_DOMAIN_1"),
			Type:                   pulumi.String("PARTNER"),
			Router:                 foobar.ID(),
			Mtu:                    pulumi.String("1500"),
			StackType:              pulumi.String("IPV4_IPV6"),
			Labels: pulumi.StringMap{
				"mykey": pulumi.String("myvalue"),
			},
			CandidateCloudRouterIpAddress:      pulumi.String("192.169.0.1/29"),
			CandidateCustomerRouterIpAddress:   pulumi.String("192.169.0.2/29"),
			CandidateCloudRouterIpv6Address:    pulumi.String("748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125"),
			CandidateCustomerRouterIpv6Address: pulumi.String("748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125"),
		})
		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 foobarNetwork = new Gcp.Compute.Network("foobar", new()
    {
        Name = "test-network",
        AutoCreateSubnetworks = false,
    });

    var foobar = new Gcp.Compute.Router("foobar", new()
    {
        Name = "test-router",
        Network = foobarNetwork.Name,
        Bgp = new Gcp.Compute.Inputs.RouterBgpArgs
        {
            Asn = 16550,
        },
    });

    var custom_ranges_interconnect_attachment = new Gcp.Compute.InterconnectAttachment("custom-ranges-interconnect-attachment", new()
    {
        Name = "test-custom-ranges-interconnect-attachment",
        EdgeAvailabilityDomain = "AVAILABILITY_DOMAIN_1",
        Type = "PARTNER",
        Router = foobar.Id,
        Mtu = "1500",
        StackType = "IPV4_IPV6",
        Labels = 
        {
            { "mykey", "myvalue" },
        },
        CandidateCloudRouterIpAddress = "192.169.0.1/29",
        CandidateCustomerRouterIpAddress = "192.169.0.2/29",
        CandidateCloudRouterIpv6Address = "748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125",
        CandidateCustomerRouterIpv6Address = "748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125",
    });

});
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.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 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 foobarNetwork = new Network("foobarNetwork", NetworkArgs.builder()
            .name("test-network")
            .autoCreateSubnetworks(false)
            .build());

        var foobar = new Router("foobar", RouterArgs.builder()
            .name("test-router")
            .network(foobarNetwork.name())
            .bgp(RouterBgpArgs.builder()
                .asn(16550)
                .build())
            .build());

        var custom_ranges_interconnect_attachment = new InterconnectAttachment("custom-ranges-interconnect-attachment", InterconnectAttachmentArgs.builder()
            .name("test-custom-ranges-interconnect-attachment")
            .edgeAvailabilityDomain("AVAILABILITY_DOMAIN_1")
            .type("PARTNER")
            .router(foobar.id())
            .mtu("1500")
            .stackType("IPV4_IPV6")
            .labels(Map.of("mykey", "myvalue"))
            .candidateCloudRouterIpAddress("192.169.0.1/29")
            .candidateCustomerRouterIpAddress("192.169.0.2/29")
            .candidateCloudRouterIpv6Address("748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125")
            .candidateCustomerRouterIpv6Address("748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125")
            .build());

    }
}
resources:
  custom-ranges-interconnect-attachment:
    type: gcp:compute:InterconnectAttachment
    properties:
      name: test-custom-ranges-interconnect-attachment
      edgeAvailabilityDomain: AVAILABILITY_DOMAIN_1
      type: PARTNER
      router: ${foobar.id}
      mtu: 1500
      stackType: IPV4_IPV6
      labels:
        mykey: myvalue
      candidateCloudRouterIpAddress: 192.169.0.1/29
      candidateCustomerRouterIpAddress: 192.169.0.2/29
      candidateCloudRouterIpv6Address: 748d:2f23:6651:9455:828b:ca81:6fe0:fed1/125
      candidateCustomerRouterIpv6Address: 748d:2f23:6651:9455:828b:ca81:6fe0:fed2/125
  foobar:
    type: gcp:compute:Router
    properties:
      name: test-router
      network: ${foobarNetwork.name}
      bgp:
        asn: 16550
  foobarNetwork:
    type: gcp:compute:Network
    name: foobar
    properties:
      name: test-network
      autoCreateSubnetworks: false

The stackType property set to IPV4_IPV6 enables dual-stack operation. The candidateCloudRouterIpAddress and candidateCustomerRouterIpAddress properties define IPv4 addresses for the Google and customer sides of the BGP session, while candidateCloudRouterIpv6Address and candidateCustomerRouterIpv6Address define the IPv6 equivalents. All addresses must include prefix lengths (e.g., /29 for IPv4, /125 for IPv6).

Beyond these examples

These snippets focus on specific attachment-level features: partner attachments and edge availability domains, IPsec encryption with reserved addresses, and dual-stack IPv4/IPv6 configuration. They’re intentionally minimal rather than full hybrid connectivity solutions.

The examples may reference pre-existing infrastructure such as VPC networks for Cloud Router placement, and IP address ranges that don’t conflict with existing allocations. They focus on configuring the attachment rather than provisioning the surrounding network infrastructure.

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

  • DEDICATED attachment type with interconnect URL
  • Bandwidth tuning beyond default BPS_10G
  • Candidate subnet restrictions (candidateSubnets)
  • Admin state control (adminEnabled)

These omissions are intentional: the goal is to illustrate how each attachment feature is wired, not provide drop-in hybrid networking modules. See the Interconnect Attachment resource reference for all available configuration options.

Let's configure GCP Interconnect Attachments

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Attachment Types & Configuration
What's the difference between PARTNER and DEDICATED attachment types?
PARTNER attachments have bandwidth set by the Google Partner (output-only), vlanTag8021q managed upstream, and can be pre-activated with adminEnabled. DEDICATED attachments require the interconnect parameter and allow user-set bandwidth. Both types support IPSEC encryption at creation.
How is bandwidth configured for interconnect attachments?
Bandwidth defaults to BPS_10G. For PARTNER type, bandwidth is output-only and set by the Google Partner. For PARTNER_PROVIDER and DEDICATED types, users can set bandwidth from available values (BPS_50M to BPS_400G).
What MTU values are supported?
Valid MTU values are 1440 (default), 1460, 1500, and 8896 bytes.
What's the valid range for VLAN tags?
The vlanTag8021q must be in the range 2-4094. For PARTNER type, this is managed upstream by the partner.
Encryption & Security
How do I enable IPsec encryption for my interconnect attachment?
Set encryption to IPSEC (can only be specified at creation for PARTNER or DEDICATED types), provide ipsecInternalAddresses with RFC 1918 IP ranges, and configure the router with encryptedInterconnectRouter: true.
What happens if I don't specify ipsecInternalAddresses for IPSEC encryption?
If ipsecInternalAddresses is not specified for an IPSEC-encrypted attachment, HA VPN gateway IP addresses will be allocated from the regional external IP address pool instead of the private RFC 1918 ranges.
IP Addressing & Routing
How do I configure custom IPv4 and IPv6 address ranges?
Set stackType to IPV4_IPV6 and specify candidateCloudRouterIpAddress, candidateCustomerRouterIpAddress, candidateCloudRouterIpv6Address, and candidateCustomerRouterIpv6Address with appropriate prefix lengths.
What are the subnet length options and defaults?
Allowed values are 29 (default) or 30. For Cross-Cloud Interconnect connections using Azure remote locations, the default is 30, and requesting 29 returns an error. Where both are allowed, 29 is preferred for better Google Cloud Support debugging visibility.
What are the requirements for candidateSubnets?
Up to 16 candidate prefixes within link-local address space (169.254.0.0/16), each /29 or shorter (/28, /27, etc.). Google selects an unused /29 from the supplied prefixes. The request fails if all possible /29s are in use on Google’s edge. If not supplied, Google randomly selects from all link-local space.
Does the Cloud Router need to be in the same region as the attachment?
Yes, the router must be in the same region as the InterconnectAttachment.
Immutability & Lifecycle
What properties can't be changed after creating an interconnect attachment?
The following properties are immutable: type, edgeAvailabilityDomain, encryption, router, interconnect, vlanTag8021q, candidateSubnets, subnetLength, ipsecInternalAddresses, name, project, and all candidate IP address fields. Changes require recreating the resource.
How do I manage labels on interconnect attachments?
The labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to view all labels present on the resource, including those set by other clients and services.
Reliability & Availability
How should I configure attachments for improved reliability?
For PARTNER type attachments, configure a pair of attachments with one per availability domain (edgeAvailabilityDomain). This ensures redundancy across availability domains.

Using a different cloud?

Explore networking guides for other cloud providers: