The aws:directconnect/gatewayAssociation:GatewayAssociation resource, part of the Pulumi AWS provider, connects a Direct Connect gateway to either 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 with prefix filtering, and custom CIDR advertisement.
Associations require an existing Direct Connect gateway and either a VPN gateway or transit gateway. Cross-account associations follow a separate proposal workflow not covered here. The examples are intentionally small. Combine them with your own Direct Connect infrastructure and network design.
Connect a Direct Connect gateway to a VPN gateway
Organizations with on-premises data centers use Direct Connect gateways to establish private connectivity to AWS VPCs without traversing the public internet.
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. This creates a single-account association that routes traffic between your on-premises network and the VPC. Without specifying allowedPrefixes, the association advertises the VPC’s entire CIDR block to the Direct Connect gateway.
Connect to a transit gateway with prefix filtering
Transit gateways enable hub-and-spoke network topologies that connect multiple VPCs and on-premises networks through a central routing point.
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 blocks are advertised to on-premises networks. This example advertises only two /30 subnets rather than the entire VPC range, enabling fine-grained control over which resources are reachable from on-premises.
Advertise custom CIDR blocks to on-premises networks
Some network designs require advertising specific subnets or non-VPC address ranges instead of the default VPC CIDR.
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 of advertising the VPC’s CIDR block. Here, two custom CIDR ranges are advertised to the Direct Connect gateway, which might represent specific application subnets or summarized routes. This configuration is useful when you need to control exactly which IP ranges are visible to on-premises networks.
Beyond these examples
These snippets focus on specific gateway association features: VPN gateway and transit gateway associations, and prefix filtering with allowedPrefixes. They’re intentionally minimal rather than full hybrid network architectures.
The examples may reference pre-existing infrastructure such as Direct Connect gateways (examples create inline, but typically pre-exist), and VPCs and VPN gateways or transit gateways. 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)
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 FREEFrequently Asked Questions
Cross-Account & Multi-Region Setup
GatewayAssociationProposal in the account that owns the VGW or Transit Gateway. Then, accept the proposal by creating a GatewayAssociation with proposal_id and associated_gateway_owner_account_id in the account that owns the Direct Connect Gateway.dx_gateway_id and associated_gateway_id. Cross-account associations require proposal_id and associated_gateway_owner_account_id instead, following a proposal/acceptance workflow.Gateway Types & Configuration
associated_gateway_id to the respective gateway ID.allowed_prefixes to the list of CIDR blocks you want to advertise. While it defaults to the VPC CIDR, you must explicitly configure it to enable drift detection.allowed_prefixes is explicitly configured. Without explicit configuration, Pulumi can’t detect changes to the prefixes.Immutability & Lifecycle
dx_gateway_id, associated_gateway_id, and associated_gateway_owner_account_id properties are immutable. Changing any of these requires replacing the association.pulumi import with the format dx_gateway_id/associated_gateway_id, for example: pulumi import aws:directconnect/gatewayAssociation:GatewayAssociation example 345508c3-7215-4aef-9832-07c125d5bd0f/vgw-98765432.Using a different cloud?
Explore networking guides for other cloud providers: