The aws:ec2transitgateway/routeTablePropagation:RouteTablePropagation resource, part of the Pulumi AWS provider, enables automatic route learning from Transit Gateway attachments into route tables. This guide focuses on two capabilities: VPC attachment propagation and Direct Connect Gateway propagation.
Route table propagations reference existing Transit Gateway route tables and attachments. The examples are intentionally small. Combine them with your own Transit Gateway infrastructure and routing policies.
Propagate VPC routes to a Transit Gateway route table
Most Transit Gateway deployments connect VPCs and propagate their routes automatically, eliminating manual route entries.
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 exampleRouteTablePropagation = new aws.ec2transitgateway.RouteTablePropagation("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_propagation = aws.ec2transitgateway.RouteTablePropagation("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.NewRouteTablePropagation(ctx, "example", &ec2transitgateway.RouteTablePropagationArgs{
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 exampleRouteTablePropagation = new Aws.Ec2TransitGateway.RouteTablePropagation("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.RouteTablePropagation;
import com.pulumi.aws.ec2transitgateway.RouteTablePropagationArgs;
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 exampleRouteTablePropagation = new RouteTablePropagation("exampleRouteTablePropagation", RouteTablePropagationArgs.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
exampleRouteTablePropagation:
type: aws:ec2transitgateway:RouteTablePropagation
name: example
properties:
transitGatewayAttachmentId: ${exampleVpcAttachment.id}
transitGatewayRouteTableId: ${exampleRouteTable.id}
When you create a propagation, the Transit Gateway learns routes from the VPC attachment and adds them to the route table automatically. The transitGatewayAttachmentId references the VPC attachment directly; the transitGatewayRouteTableId specifies which route table receives the routes. As subnets change in the VPC, the Transit Gateway updates routes automatically.
Propagate Direct Connect Gateway routes
Hybrid architectures use Direct Connect to link on-premises networks to AWS. Propagating these routes enables VPCs to reach on-premises resources.
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 exampleRouteTablePropagation = new aws.ec2transitgateway.RouteTablePropagation("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_propagation = aws.ec2transitgateway.RouteTablePropagation("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.NewRouteTablePropagation(ctx, "example", &ec2transitgateway.RouteTablePropagationArgs{
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 exampleRouteTablePropagation = new Aws.Ec2TransitGateway.RouteTablePropagation("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.RouteTablePropagation;
import com.pulumi.aws.ec2transitgateway.RouteTablePropagationArgs;
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 exampleRouteTablePropagation = new RouteTablePropagation("exampleRouteTablePropagation", RouteTablePropagationArgs.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
exampleRouteTablePropagation:
type: aws:ec2transitgateway:RouteTablePropagation
name: example
properties:
transitGatewayAttachmentId: ${exampleGatewayAssociation.transitGatewayAttachmentId}
transitGatewayRouteTableId: ${exampleRouteTable.id}
The GatewayAssociation resource connects your Direct Connect Gateway to the Transit Gateway and exposes a transitGatewayAttachmentId attribute. Reference this attribute directly in the propagation rather than using a data source lookup. The allowedPrefixes property on the association controls which on-premises routes are advertised to AWS.
Beyond these examples
These snippets focus on specific propagation features: VPC attachment propagation and Direct Connect Gateway propagation. They’re intentionally minimal rather than complete Transit Gateway deployments.
The examples may reference pre-existing infrastructure such as Transit Gateway and route table resources, and VPC attachments or Direct Connect Gateway associations. They focus on configuring propagation rather than provisioning the entire Transit Gateway topology.
To keep things focused, common propagation patterns are omitted, including:
- Region-specific placement (region property)
- Static route entries (separate RouteTableRoute resource)
- Route table associations (separate RouteTableAssociation resource)
- Propagation filtering or route manipulation
These omissions are intentional: the goal is to illustrate how route propagation is wired, not provide drop-in networking modules. See the Transit Gateway Route Table Propagation resource reference for all available configuration options.
Let's configure AWS Transit Gateway Route Table Propagation
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 unnecessary recreation when unrelated attributes like allowedPrefixes change. Instead, reference the transitGatewayAttachmentId attribute directly from the aws.directconnect.GatewayAssociation resource.transitGatewayAttachmentId changes (for example, when a VPC attachment is replaced), the propagation resource is recreated. This is expected behavior to maintain consistency between the attachment and its route table propagation.Configuration & Setup
transitGatewayAttachmentId and transitGatewayRouteTableId are required and immutable. Changing either property after creation will force resource replacement.id attribute directly in transitGatewayAttachmentId. Avoid using data sources or lifecycle rules that might cause the attachment ID to become unknown during planning.Direct Connect Gateway Integration
transitGatewayAttachmentId attribute directly from the aws.directconnect.GatewayAssociation resource (available in v6.5.0+). This prevents unnecessary recreation when association attributes change.Using a different cloud?
Explore networking guides for other cloud providers: