Configure AWS Direct Connect Gateway Associations

The aws:directconnect/gatewayAssociation:GatewayAssociation resource, part of the Pulumi AWS provider, links a Direct Connect gateway to a VPN gateway or transit gateway, enabling private connectivity between on-premises networks and AWS VPCs. This guide focuses on three capabilities: VPN gateway associations, transit gateway associations, and route advertisement control via allowed prefixes.

Associations require an existing Direct Connect gateway and either a VPN gateway or transit gateway. The examples are intentionally small. Combine them with your own Direct Connect infrastructure and network topology.

Connect a Direct Connect gateway to a VPN gateway

Organizations with on-premises data centers establish private connectivity to AWS VPCs by associating Direct Connect gateways with VPN gateways.

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

const example = new aws.directconnect.Gateway("example", {
    name: "example",
    amazonSideAsn: "64512",
});
const exampleVpc = new aws.ec2.Vpc("example", {cidrBlock: "10.255.255.0/28"});
const exampleVpnGateway = new aws.ec2.VpnGateway("example", {vpcId: exampleVpc.id});
const exampleGatewayAssociation = new aws.directconnect.GatewayAssociation("example", {
    dxGatewayId: example.id,
    associatedGatewayId: exampleVpnGateway.id,
});
import pulumi
import pulumi_aws as aws

example = aws.directconnect.Gateway("example",
    name="example",
    amazon_side_asn="64512")
example_vpc = aws.ec2.Vpc("example", cidr_block="10.255.255.0/28")
example_vpn_gateway = aws.ec2.VpnGateway("example", vpc_id=example_vpc.id)
example_gateway_association = aws.directconnect.GatewayAssociation("example",
    dx_gateway_id=example.id,
    associated_gateway_id=example_vpn_gateway.id)
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directconnect"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := directconnect.NewGateway(ctx, "example", &directconnect.GatewayArgs{
			Name:          pulumi.String("example"),
			AmazonSideAsn: pulumi.String("64512"),
		})
		if err != nil {
			return err
		}
		exampleVpc, err := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
			CidrBlock: pulumi.String("10.255.255.0/28"),
		})
		if err != nil {
			return err
		}
		exampleVpnGateway, err := ec2.NewVpnGateway(ctx, "example", &ec2.VpnGatewayArgs{
			VpcId: exampleVpc.ID(),
		})
		if err != nil {
			return err
		}
		_, err = directconnect.NewGatewayAssociation(ctx, "example", &directconnect.GatewayAssociationArgs{
			DxGatewayId:         example.ID(),
			AssociatedGatewayId: exampleVpnGateway.ID(),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DirectConnect.Gateway("example", new()
    {
        Name = "example",
        AmazonSideAsn = "64512",
    });

    var exampleVpc = new Aws.Ec2.Vpc("example", new()
    {
        CidrBlock = "10.255.255.0/28",
    });

    var exampleVpnGateway = new Aws.Ec2.VpnGateway("example", new()
    {
        VpcId = exampleVpc.Id,
    });

    var exampleGatewayAssociation = new Aws.DirectConnect.GatewayAssociation("example", new()
    {
        DxGatewayId = example.Id,
        AssociatedGatewayId = exampleVpnGateway.Id,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.directconnect.Gateway;
import com.pulumi.aws.directconnect.GatewayArgs;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.VpnGateway;
import com.pulumi.aws.ec2.VpnGatewayArgs;
import com.pulumi.aws.directconnect.GatewayAssociation;
import com.pulumi.aws.directconnect.GatewayAssociationArgs;
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 example = new Gateway("example", GatewayArgs.builder()
            .name("example")
            .amazonSideAsn("64512")
            .build());

        var exampleVpc = new Vpc("exampleVpc", VpcArgs.builder()
            .cidrBlock("10.255.255.0/28")
            .build());

        var exampleVpnGateway = new VpnGateway("exampleVpnGateway", VpnGatewayArgs.builder()
            .vpcId(exampleVpc.id())
            .build());

        var exampleGatewayAssociation = new GatewayAssociation("exampleGatewayAssociation", GatewayAssociationArgs.builder()
            .dxGatewayId(example.id())
            .associatedGatewayId(exampleVpnGateway.id())
            .build());

    }
}
resources:
  example:
    type: aws:directconnect:Gateway
    properties:
      name: example
      amazonSideAsn: '64512'
  exampleVpc:
    type: aws:ec2:Vpc
    name: example
    properties:
      cidrBlock: 10.255.255.0/28
  exampleVpnGateway:
    type: aws:ec2:VpnGateway
    name: example
    properties:
      vpcId: ${exampleVpc.id}
  exampleGatewayAssociation:
    type: aws:directconnect:GatewayAssociation
    name: example
    properties:
      dxGatewayId: ${example.id}
      associatedGatewayId: ${exampleVpnGateway.id}

The dxGatewayId identifies your Direct Connect gateway, while associatedGatewayId points to the VPN gateway attached to your VPC. Without explicit allowedPrefixes configuration, the association advertises the VPC’s entire CIDR block to your on-premises network.

Connect a Direct Connect gateway to a transit gateway

Transit gateways act as regional network hubs, connecting multiple VPCs and on-premises networks through a single Direct Connect gateway association.

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

const example = new aws.directconnect.Gateway("example", {
    name: "example",
    amazonSideAsn: "64512",
});
const exampleTransitGateway = new aws.ec2transitgateway.TransitGateway("example", {});
const exampleGatewayAssociation = new aws.directconnect.GatewayAssociation("example", {
    dxGatewayId: example.id,
    associatedGatewayId: exampleTransitGateway.id,
    allowedPrefixes: [
        "10.255.255.0/30",
        "10.255.255.8/30",
    ],
});
import pulumi
import pulumi_aws as aws

example = aws.directconnect.Gateway("example",
    name="example",
    amazon_side_asn="64512")
example_transit_gateway = aws.ec2transitgateway.TransitGateway("example")
example_gateway_association = aws.directconnect.GatewayAssociation("example",
    dx_gateway_id=example.id,
    associated_gateway_id=example_transit_gateway.id,
    allowed_prefixes=[
        "10.255.255.0/30",
        "10.255.255.8/30",
    ])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directconnect"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2transitgateway"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := directconnect.NewGateway(ctx, "example", &directconnect.GatewayArgs{
			Name:          pulumi.String("example"),
			AmazonSideAsn: pulumi.String("64512"),
		})
		if err != nil {
			return err
		}
		exampleTransitGateway, err := ec2transitgateway.NewTransitGateway(ctx, "example", nil)
		if err != nil {
			return err
		}
		_, err = directconnect.NewGatewayAssociation(ctx, "example", &directconnect.GatewayAssociationArgs{
			DxGatewayId:         example.ID(),
			AssociatedGatewayId: exampleTransitGateway.ID(),
			AllowedPrefixes: pulumi.StringArray{
				pulumi.String("10.255.255.0/30"),
				pulumi.String("10.255.255.8/30"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DirectConnect.Gateway("example", new()
    {
        Name = "example",
        AmazonSideAsn = "64512",
    });

    var exampleTransitGateway = new Aws.Ec2TransitGateway.TransitGateway("example");

    var exampleGatewayAssociation = new Aws.DirectConnect.GatewayAssociation("example", new()
    {
        DxGatewayId = example.Id,
        AssociatedGatewayId = exampleTransitGateway.Id,
        AllowedPrefixes = new[]
        {
            "10.255.255.0/30",
            "10.255.255.8/30",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.directconnect.Gateway;
import com.pulumi.aws.directconnect.GatewayArgs;
import com.pulumi.aws.ec2transitgateway.TransitGateway;
import com.pulumi.aws.directconnect.GatewayAssociation;
import com.pulumi.aws.directconnect.GatewayAssociationArgs;
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 example = new Gateway("example", GatewayArgs.builder()
            .name("example")
            .amazonSideAsn("64512")
            .build());

        var exampleTransitGateway = new TransitGateway("exampleTransitGateway");

        var exampleGatewayAssociation = new GatewayAssociation("exampleGatewayAssociation", GatewayAssociationArgs.builder()
            .dxGatewayId(example.id())
            .associatedGatewayId(exampleTransitGateway.id())
            .allowedPrefixes(            
                "10.255.255.0/30",
                "10.255.255.8/30")
            .build());

    }
}
resources:
  example:
    type: aws:directconnect:Gateway
    properties:
      name: example
      amazonSideAsn: '64512'
  exampleTransitGateway:
    type: aws:ec2transitgateway:TransitGateway
    name: example
  exampleGatewayAssociation:
    type: aws:directconnect:GatewayAssociation
    name: example
    properties:
      dxGatewayId: ${example.id}
      associatedGatewayId: ${exampleTransitGateway.id}
      allowedPrefixes:
        - 10.255.255.0/30
        - 10.255.255.8/30

When associating with a transit gateway, the allowedPrefixes property controls which CIDR ranges are advertised to your on-premises network. This enables selective routing across your multi-VPC topology.

Control route advertisement with allowed prefixes

By default, associations advertise the entire VPC CIDR block. Some deployments need to advertise only specific subnets to control routing and limit exposure.

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

const example = new aws.directconnect.Gateway("example", {
    name: "example",
    amazonSideAsn: "64512",
});
const exampleVpc = new aws.ec2.Vpc("example", {cidrBlock: "10.255.255.0/28"});
const exampleVpnGateway = new aws.ec2.VpnGateway("example", {vpcId: exampleVpc.id});
const exampleGatewayAssociation = new aws.directconnect.GatewayAssociation("example", {
    dxGatewayId: example.id,
    associatedGatewayId: exampleVpnGateway.id,
    allowedPrefixes: [
        "210.52.109.0/24",
        "175.45.176.0/22",
    ],
});
import pulumi
import pulumi_aws as aws

example = aws.directconnect.Gateway("example",
    name="example",
    amazon_side_asn="64512")
example_vpc = aws.ec2.Vpc("example", cidr_block="10.255.255.0/28")
example_vpn_gateway = aws.ec2.VpnGateway("example", vpc_id=example_vpc.id)
example_gateway_association = aws.directconnect.GatewayAssociation("example",
    dx_gateway_id=example.id,
    associated_gateway_id=example_vpn_gateway.id,
    allowed_prefixes=[
        "210.52.109.0/24",
        "175.45.176.0/22",
    ])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directconnect"
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := directconnect.NewGateway(ctx, "example", &directconnect.GatewayArgs{
			Name:          pulumi.String("example"),
			AmazonSideAsn: pulumi.String("64512"),
		})
		if err != nil {
			return err
		}
		exampleVpc, err := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
			CidrBlock: pulumi.String("10.255.255.0/28"),
		})
		if err != nil {
			return err
		}
		exampleVpnGateway, err := ec2.NewVpnGateway(ctx, "example", &ec2.VpnGatewayArgs{
			VpcId: exampleVpc.ID(),
		})
		if err != nil {
			return err
		}
		_, err = directconnect.NewGatewayAssociation(ctx, "example", &directconnect.GatewayAssociationArgs{
			DxGatewayId:         example.ID(),
			AssociatedGatewayId: exampleVpnGateway.ID(),
			AllowedPrefixes: pulumi.StringArray{
				pulumi.String("210.52.109.0/24"),
				pulumi.String("175.45.176.0/22"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DirectConnect.Gateway("example", new()
    {
        Name = "example",
        AmazonSideAsn = "64512",
    });

    var exampleVpc = new Aws.Ec2.Vpc("example", new()
    {
        CidrBlock = "10.255.255.0/28",
    });

    var exampleVpnGateway = new Aws.Ec2.VpnGateway("example", new()
    {
        VpcId = exampleVpc.Id,
    });

    var exampleGatewayAssociation = new Aws.DirectConnect.GatewayAssociation("example", new()
    {
        DxGatewayId = example.Id,
        AssociatedGatewayId = exampleVpnGateway.Id,
        AllowedPrefixes = new[]
        {
            "210.52.109.0/24",
            "175.45.176.0/22",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.directconnect.Gateway;
import com.pulumi.aws.directconnect.GatewayArgs;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.VpnGateway;
import com.pulumi.aws.ec2.VpnGatewayArgs;
import com.pulumi.aws.directconnect.GatewayAssociation;
import com.pulumi.aws.directconnect.GatewayAssociationArgs;
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 example = new Gateway("example", GatewayArgs.builder()
            .name("example")
            .amazonSideAsn("64512")
            .build());

        var exampleVpc = new Vpc("exampleVpc", VpcArgs.builder()
            .cidrBlock("10.255.255.0/28")
            .build());

        var exampleVpnGateway = new VpnGateway("exampleVpnGateway", VpnGatewayArgs.builder()
            .vpcId(exampleVpc.id())
            .build());

        var exampleGatewayAssociation = new GatewayAssociation("exampleGatewayAssociation", GatewayAssociationArgs.builder()
            .dxGatewayId(example.id())
            .associatedGatewayId(exampleVpnGateway.id())
            .allowedPrefixes(            
                "210.52.109.0/24",
                "175.45.176.0/22")
            .build());

    }
}
resources:
  example:
    type: aws:directconnect:Gateway
    properties:
      name: example
      amazonSideAsn: '64512'
  exampleVpc:
    type: aws:ec2:Vpc
    name: example
    properties:
      cidrBlock: 10.255.255.0/28
  exampleVpnGateway:
    type: aws:ec2:VpnGateway
    name: example
    properties:
      vpcId: ${exampleVpc.id}
  exampleGatewayAssociation:
    type: aws:directconnect:GatewayAssociation
    name: example
    properties:
      dxGatewayId: ${example.id}
      associatedGatewayId: ${exampleVpnGateway.id}
      allowedPrefixes:
        - 210.52.109.0/24
        - 175.45.176.0/22

The allowedPrefixes property overrides the default behavior, advertising only the specified CIDR ranges to your on-premises network. This provides fine-grained control over which AWS resources are reachable from your data center.

Beyond these examples

These snippets focus on specific gateway association features: VPN gateway and transit gateway associations, and route advertisement control. They’re intentionally minimal rather than full hybrid network deployments.

The examples assume pre-existing infrastructure such as Direct Connect gateway, VPN gateway or transit gateway, and VPC with configured CIDR blocks. They focus on configuring the association rather than provisioning the underlying network infrastructure.

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

  • Cross-account associations (proposalId and associatedGatewayOwnerAccountId)
  • Multi-region gateway associations (region property and provider aliases)

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

Let's configure AWS Direct Connect Gateway Associations

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Cross-Account & Cross-Region Setup
How do I create a cross-account Direct Connect gateway association?
Create an aws.directconnect.GatewayAssociationProposal in the account owning the VGW or transit gateway. Then, in the account owning the Direct Connect gateway, create an aws.directconnect.GatewayAssociation with proposalId and associatedGatewayOwnerAccountId set.
How do I associate a gateway in another region?
If the associatedGatewayId is in a different region, create a provider alias for that region and reference it in your resource configuration.
What parameters are required for single-account associations?
For single-account associations, you must specify both dxGatewayId and associatedGatewayId.
Configuration & Gateway Types
What types of gateways can I associate with a Direct Connect gateway?
You can associate either a Virtual Private Gateway (VPN Gateway) or a Transit Gateway. The associatedGatewayType output will be virtualPrivateGateway or transitGateway.
What are allowed prefixes and when should I configure them?
Allowed prefixes are VPC CIDR blocks advertised to the Direct Connect gateway. They default to the VPC CIDR, but you must explicitly configure them to enable drift detection.
Drift Detection & State Management
Why should I always configure allowedPrefixes explicitly?
Even though allowedPrefixes defaults to the VPC CIDR, you must configure it explicitly to enable drift detection. Without this, Pulumi may not detect changes to the allowed prefixes.
Immutability & Lifecycle
What properties can't be changed after creating the association?
The dxGatewayId, associatedGatewayId, and associatedGatewayOwnerAccountId properties are immutable. Changing any of these requires recreating the association.
Can I change the associated gateway after creation?
No, the associatedGatewayId is immutable. To associate a different gateway, you must delete and recreate the association.

Using a different cloud?

Explore networking guides for other cloud providers: