The aws:ec2transitgateway/routeTableAssociation:RouteTableAssociation resource, part of the Pulumi AWS provider, links Transit Gateway attachments to route tables, controlling which routes each attachment can access. This guide focuses on two capabilities: VPC attachment associations and Direct Connect Gateway associations.
Route table associations depend on existing Transit Gateway attachments and route tables. The attachment ID must be referenced directly from the attachment resource to avoid unnecessary recreation. The examples are intentionally small. Combine them with your own Transit Gateway infrastructure and routing policies.
Associate a VPC attachment with a route table
Transit Gateway route tables control traffic flow between attached networks. Most deployments associate VPC attachments with route tables to enable inter-VPC routing.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.ec2.Vpc("example", {cidrBlock: "10.0.0.0/16"});
const exampleSubnet = new aws.ec2.Subnet("example", {
vpcId: example.id,
cidrBlock: "10.0.1.0/24",
});
const exampleTransitGateway = new aws.ec2transitgateway.TransitGateway("example", {description: "example"});
const exampleVpcAttachment = new aws.ec2transitgateway.VpcAttachment("example", {
subnetIds: [exampleSubnet.id],
transitGatewayId: exampleTransitGateway.id,
vpcId: example.id,
});
const exampleRouteTable = new aws.ec2transitgateway.RouteTable("example", {transitGatewayId: exampleTransitGateway.id});
// Correct: Reference the VPC attachment ID directly
const exampleRouteTableAssociation = new aws.ec2transitgateway.RouteTableAssociation("example", {
transitGatewayAttachmentId: exampleVpcAttachment.id,
transitGatewayRouteTableId: exampleRouteTable.id,
});
import pulumi
import pulumi_aws as aws
example = aws.ec2.Vpc("example", cidr_block="10.0.0.0/16")
example_subnet = aws.ec2.Subnet("example",
vpc_id=example.id,
cidr_block="10.0.1.0/24")
example_transit_gateway = aws.ec2transitgateway.TransitGateway("example", description="example")
example_vpc_attachment = aws.ec2transitgateway.VpcAttachment("example",
subnet_ids=[example_subnet.id],
transit_gateway_id=example_transit_gateway.id,
vpc_id=example.id)
example_route_table = aws.ec2transitgateway.RouteTable("example", transit_gateway_id=example_transit_gateway.id)
# Correct: Reference the VPC attachment ID directly
example_route_table_association = aws.ec2transitgateway.RouteTableAssociation("example",
transit_gateway_attachment_id=example_vpc_attachment.id,
transit_gateway_route_table_id=example_route_table.id)
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"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 := ec2.NewVpc(ctx, "example", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
exampleSubnet, err := ec2.NewSubnet(ctx, "example", &ec2.SubnetArgs{
VpcId: example.ID(),
CidrBlock: pulumi.String("10.0.1.0/24"),
})
if err != nil {
return err
}
exampleTransitGateway, err := ec2transitgateway.NewTransitGateway(ctx, "example", &ec2transitgateway.TransitGatewayArgs{
Description: pulumi.String("example"),
})
if err != nil {
return err
}
exampleVpcAttachment, err := ec2transitgateway.NewVpcAttachment(ctx, "example", &ec2transitgateway.VpcAttachmentArgs{
SubnetIds: pulumi.StringArray{
exampleSubnet.ID(),
},
TransitGatewayId: exampleTransitGateway.ID(),
VpcId: example.ID(),
})
if err != nil {
return err
}
exampleRouteTable, err := ec2transitgateway.NewRouteTable(ctx, "example", &ec2transitgateway.RouteTableArgs{
TransitGatewayId: exampleTransitGateway.ID(),
})
if err != nil {
return err
}
// Correct: Reference the VPC attachment ID directly
_, err = ec2transitgateway.NewRouteTableAssociation(ctx, "example", &ec2transitgateway.RouteTableAssociationArgs{
TransitGatewayAttachmentId: exampleVpcAttachment.ID(),
TransitGatewayRouteTableId: exampleRouteTable.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.Ec2.Vpc("example", new()
{
CidrBlock = "10.0.0.0/16",
});
var exampleSubnet = new Aws.Ec2.Subnet("example", new()
{
VpcId = example.Id,
CidrBlock = "10.0.1.0/24",
});
var exampleTransitGateway = new Aws.Ec2TransitGateway.TransitGateway("example", new()
{
Description = "example",
});
var exampleVpcAttachment = new Aws.Ec2TransitGateway.VpcAttachment("example", new()
{
SubnetIds = new[]
{
exampleSubnet.Id,
},
TransitGatewayId = exampleTransitGateway.Id,
VpcId = example.Id,
});
var exampleRouteTable = new Aws.Ec2TransitGateway.RouteTable("example", new()
{
TransitGatewayId = exampleTransitGateway.Id,
});
// Correct: Reference the VPC attachment ID directly
var exampleRouteTableAssociation = new Aws.Ec2TransitGateway.RouteTableAssociation("example", new()
{
TransitGatewayAttachmentId = exampleVpcAttachment.Id,
TransitGatewayRouteTableId = exampleRouteTable.Id,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.ec2transitgateway.TransitGateway;
import com.pulumi.aws.ec2transitgateway.TransitGatewayArgs;
import com.pulumi.aws.ec2transitgateway.VpcAttachment;
import com.pulumi.aws.ec2transitgateway.VpcAttachmentArgs;
import com.pulumi.aws.ec2transitgateway.RouteTable;
import com.pulumi.aws.ec2transitgateway.RouteTableArgs;
import com.pulumi.aws.ec2transitgateway.RouteTableAssociation;
import com.pulumi.aws.ec2transitgateway.RouteTableAssociationArgs;
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 Vpc("example", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var exampleSubnet = new Subnet("exampleSubnet", SubnetArgs.builder()
.vpcId(example.id())
.cidrBlock("10.0.1.0/24")
.build());
var exampleTransitGateway = new TransitGateway("exampleTransitGateway", TransitGatewayArgs.builder()
.description("example")
.build());
var exampleVpcAttachment = new VpcAttachment("exampleVpcAttachment", VpcAttachmentArgs.builder()
.subnetIds(exampleSubnet.id())
.transitGatewayId(exampleTransitGateway.id())
.vpcId(example.id())
.build());
var exampleRouteTable = new RouteTable("exampleRouteTable", RouteTableArgs.builder()
.transitGatewayId(exampleTransitGateway.id())
.build());
// Correct: Reference the VPC attachment ID directly
var exampleRouteTableAssociation = new RouteTableAssociation("exampleRouteTableAssociation", RouteTableAssociationArgs.builder()
.transitGatewayAttachmentId(exampleVpcAttachment.id())
.transitGatewayRouteTableId(exampleRouteTable.id())
.build());
}
}
resources:
example:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
exampleSubnet:
type: aws:ec2:Subnet
name: example
properties:
vpcId: ${example.id}
cidrBlock: 10.0.1.0/24
exampleTransitGateway:
type: aws:ec2transitgateway:TransitGateway
name: example
properties:
description: example
exampleVpcAttachment:
type: aws:ec2transitgateway:VpcAttachment
name: example
properties:
subnetIds:
- ${exampleSubnet.id}
transitGatewayId: ${exampleTransitGateway.id}
vpcId: ${example.id}
exampleRouteTable:
type: aws:ec2transitgateway:RouteTable
name: example
properties:
transitGatewayId: ${exampleTransitGateway.id}
# Correct: Reference the VPC attachment ID directly
exampleRouteTableAssociation:
type: aws:ec2transitgateway:RouteTableAssociation
name: example
properties:
transitGatewayAttachmentId: ${exampleVpcAttachment.id}
transitGatewayRouteTableId: ${exampleRouteTable.id}
The transitGatewayAttachmentId references the VPC attachment directly via its id attribute. The transitGatewayRouteTableId specifies which route table controls this attachment’s routing. When the attachment is replaced, this association is automatically recreated to maintain consistency.
Associate a Direct Connect Gateway with a route table
Organizations connecting on-premises networks via Direct Connect associate the Direct Connect Gateway attachment with a route table to enable hybrid routing.
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", {description: "example"});
const exampleGatewayAssociation = new aws.directconnect.GatewayAssociation("example", {
dxGatewayId: example.id,
associatedGatewayId: exampleTransitGateway.id,
allowedPrefixes: ["10.0.0.0/16"],
});
const exampleRouteTable = new aws.ec2transitgateway.RouteTable("example", {transitGatewayId: exampleTransitGateway.id});
// Correct: Reference the attachment ID directly from the association resource
const exampleRouteTableAssociation = new aws.ec2transitgateway.RouteTableAssociation("example", {
transitGatewayAttachmentId: exampleGatewayAssociation.transitGatewayAttachmentId,
transitGatewayRouteTableId: exampleRouteTable.id,
});
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", description="example")
example_gateway_association = aws.directconnect.GatewayAssociation("example",
dx_gateway_id=example.id,
associated_gateway_id=example_transit_gateway.id,
allowed_prefixes=["10.0.0.0/16"])
example_route_table = aws.ec2transitgateway.RouteTable("example", transit_gateway_id=example_transit_gateway.id)
# Correct: Reference the attachment ID directly from the association resource
example_route_table_association = aws.ec2transitgateway.RouteTableAssociation("example",
transit_gateway_attachment_id=example_gateway_association.transit_gateway_attachment_id,
transit_gateway_route_table_id=example_route_table.id)
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", &ec2transitgateway.TransitGatewayArgs{
Description: pulumi.String("example"),
})
if err != nil {
return err
}
exampleGatewayAssociation, err := directconnect.NewGatewayAssociation(ctx, "example", &directconnect.GatewayAssociationArgs{
DxGatewayId: example.ID(),
AssociatedGatewayId: exampleTransitGateway.ID(),
AllowedPrefixes: pulumi.StringArray{
pulumi.String("10.0.0.0/16"),
},
})
if err != nil {
return err
}
exampleRouteTable, err := ec2transitgateway.NewRouteTable(ctx, "example", &ec2transitgateway.RouteTableArgs{
TransitGatewayId: exampleTransitGateway.ID(),
})
if err != nil {
return err
}
// Correct: Reference the attachment ID directly from the association resource
_, err = ec2transitgateway.NewRouteTableAssociation(ctx, "example", &ec2transitgateway.RouteTableAssociationArgs{
TransitGatewayAttachmentId: exampleGatewayAssociation.TransitGatewayAttachmentId,
TransitGatewayRouteTableId: exampleRouteTable.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 exampleTransitGateway = new Aws.Ec2TransitGateway.TransitGateway("example", new()
{
Description = "example",
});
var exampleGatewayAssociation = new Aws.DirectConnect.GatewayAssociation("example", new()
{
DxGatewayId = example.Id,
AssociatedGatewayId = exampleTransitGateway.Id,
AllowedPrefixes = new[]
{
"10.0.0.0/16",
},
});
var exampleRouteTable = new Aws.Ec2TransitGateway.RouteTable("example", new()
{
TransitGatewayId = exampleTransitGateway.Id,
});
// Correct: Reference the attachment ID directly from the association resource
var exampleRouteTableAssociation = new Aws.Ec2TransitGateway.RouteTableAssociation("example", new()
{
TransitGatewayAttachmentId = exampleGatewayAssociation.TransitGatewayAttachmentId,
TransitGatewayRouteTableId = exampleRouteTable.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.ec2transitgateway.TransitGateway;
import com.pulumi.aws.ec2transitgateway.TransitGatewayArgs;
import com.pulumi.aws.directconnect.GatewayAssociation;
import com.pulumi.aws.directconnect.GatewayAssociationArgs;
import com.pulumi.aws.ec2transitgateway.RouteTable;
import com.pulumi.aws.ec2transitgateway.RouteTableArgs;
import com.pulumi.aws.ec2transitgateway.RouteTableAssociation;
import com.pulumi.aws.ec2transitgateway.RouteTableAssociationArgs;
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", TransitGatewayArgs.builder()
.description("example")
.build());
var exampleGatewayAssociation = new GatewayAssociation("exampleGatewayAssociation", GatewayAssociationArgs.builder()
.dxGatewayId(example.id())
.associatedGatewayId(exampleTransitGateway.id())
.allowedPrefixes("10.0.0.0/16")
.build());
var exampleRouteTable = new RouteTable("exampleRouteTable", RouteTableArgs.builder()
.transitGatewayId(exampleTransitGateway.id())
.build());
// Correct: Reference the attachment ID directly from the association resource
var exampleRouteTableAssociation = new RouteTableAssociation("exampleRouteTableAssociation", RouteTableAssociationArgs.builder()
.transitGatewayAttachmentId(exampleGatewayAssociation.transitGatewayAttachmentId())
.transitGatewayRouteTableId(exampleRouteTable.id())
.build());
}
}
resources:
example:
type: aws:directconnect:Gateway
properties:
name: example
amazonSideAsn: 64512
exampleTransitGateway:
type: aws:ec2transitgateway:TransitGateway
name: example
properties:
description: example
exampleGatewayAssociation:
type: aws:directconnect:GatewayAssociation
name: example
properties:
dxGatewayId: ${example.id}
associatedGatewayId: ${exampleTransitGateway.id}
allowedPrefixes:
- 10.0.0.0/16
exampleRouteTable:
type: aws:ec2transitgateway:RouteTable
name: example
properties:
transitGatewayId: ${exampleTransitGateway.id}
# Correct: Reference the attachment ID directly from the association resource
exampleRouteTableAssociation:
type: aws:ec2transitgateway:RouteTableAssociation
name: example
properties:
transitGatewayAttachmentId: ${exampleGatewayAssociation.transitGatewayAttachmentId}
transitGatewayRouteTableId: ${exampleRouteTable.id}
The transitGatewayAttachmentId must reference the transitGatewayAttachmentId attribute directly from the GatewayAssociation resource. Avoid using data sources to retrieve the attachment ID; changes to unrelated properties like allowedPrefixes can trigger unnecessary recreation when using data sources.
Beyond these examples
These snippets focus on specific route table association features: VPC and Direct Connect Gateway attachment associations. They’re intentionally minimal rather than full Transit Gateway deployments.
The examples require pre-existing infrastructure such as Transit Gateway and route table, and VPC or Direct Connect Gateway attachments. They focus on configuring the association rather than provisioning the underlying Transit Gateway infrastructure.
To keep things focused, association patterns are omitted, including:
- Replacing existing associations (replaceExistingAssociation for shared Transit Gateways)
- Default route table association control (handled via VpcAttachment resource)
These omissions are intentional: the goal is to illustrate how attachment-to-route-table binding works, not provide drop-in networking modules. See the Transit Gateway Route Table Association resource reference for all available configuration options.
Let's configure AWS Transit Gateway Route Table Associations
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Attachment References & Best Practices
transitGatewayAttachmentId attribute from aws.directconnect.GatewayAssociation. For VPC attachments, use the id attribute from aws.ec2transitgateway.VpcAttachment. Avoid using data sources, as they can cause unnecessary recreation when unrelated attributes change or make the attachment ID unknown during planning.aws.ec2transitgateway.getDirectConnectGatewayAttachment data source causes recreation when unrelated attributes like allowed_prefixes change. Instead, reference the transitGatewayAttachmentId attribute directly from the aws.directconnect.GatewayAssociation resource (available in v6.5.0+).Configuration & Shared Gateways
replaceExistingAssociation (default: false) when working with Transit Gateways shared into your account, to remove any existing route table association before creating a new one. For Transit Gateways you own, use the transitGatewayDefaultRouteTableAssociation argument on the aws.ec2transitgateway.VpcAttachment resource instead.transitGatewayAttachmentId and transitGatewayRouteTableId are immutable. Changing either property requires recreating the association resource.Resource Behavior & Lifecycle
transitGatewayAttachmentId changes (for example, when a VPC attachment is replaced), the association resource recreates automatically. This is expected behavior to maintain consistency between the attachment and its route table association.Using a different cloud?
Explore networking guides for other cloud providers: