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 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’s ID directly. The transitGatewayRouteTableId specifies which route table controls this attachment’s routing. When the VPC attachment is replaced, this association recreates automatically 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 comes from the GatewayAssociation resource’s transitGatewayAttachmentId attribute. Reference this attribute directly rather than using a data source; data sources can cause unnecessary recreation when unrelated properties like allowedPrefixes change.
Beyond these examples
These snippets focus on specific route table association features: VPC and Direct Connect Gateway attachment associations, and route table assignment for traffic control. They’re intentionally minimal rather than full Transit Gateway topologies.
The examples reference pre-existing infrastructure such as Transit Gateway and route tables, and VPC attachments or Direct Connect Gateway associations. They focus on creating the association rather than provisioning the underlying attachments.
To keep things focused, common association patterns are omitted, including:
- Replacing existing associations (replaceExistingAssociation)
- Cross-account Transit Gateway scenarios
- VPN attachment associations
- Peering attachment associations
These omissions are intentional: the goal is to illustrate how each association type is wired, 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
Common Issues & Pitfalls
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.transitGatewayAttachmentId changes (for example, when a VPC attachment is replaced), the association recreates to maintain consistency. This is expected and correct behavior.Configuration & Setup
transitGatewayAttachmentId attribute from aws.directconnect.GatewayAssociation. For VPC attachments, use the id attribute from aws.ec2transitgateway.VpcAttachment. Avoid using data sources or lifecycle rules that might make the attachment ID unknown during planning.replaceExistingAssociation (set to true) when working with Transit Gateways shared into your account to remove existing route table associations before creating new ones. For Transit Gateways you own, use the transitGatewayDefaultRouteTableAssociation argument on the aws.ec2transitgateway.VpcAttachment resource instead.Resource Behavior
transitGatewayAttachmentId and transitGatewayRouteTableId are immutable and cannot be changed after creation.Using a different cloud?
Explore networking guides for other cloud providers: