Skip to content

Commit

Permalink
feat(ec2-alpha): add Transit Gateway L2 (#32956)
Browse files Browse the repository at this point in the history
### Issue # (if applicable)

Closes #17528

### Description of changes

Create new Transit Gateway L2 with the following constructs:
 * `TransitGateway`
 * `TransitGatewayRouteTable`
 * `TransitGatewayRoute`
 * `TransitGatewayVpcAttachment`
 * `TransitGatewayRouteTableAssociation`
 * `TransitGatewayRouteTablePropagation`

#### Important Design Decision
As described in the README, the CDK disables the creation of the default
route table by EC2 and instead the CDK will create a "custom" default
route table in its place. This is primarily because there is no way to
obtain the route table ID of the EC2 created default route table without
a custom resource.

The CDK will disable the `defaultRouteTablePropagation` and
`defaultRouteTableAssociation` properties on the L1 (when both are
disabled, EC2 does not create the default route table), but the
properties are still exposed on the CDK TransitGateway interface to
allow it to be toggled for the CDK created default route table. The
automatic association/propagation is being mimicked by CDK
implementation and not relying on the actual EC2 feature.

### Describe any new or updated permissions being added

n/a


### Description of how you validated changes

Unit + Integration tests to verify that the deployed resources behave as
expected.

### Checklist
- [x] My code adheres to the [CONTRIBUTING
GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and
[DESIGN
GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache-2.0 license*

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
paulhcsun and mergify[bot] authored Feb 3, 2025
1 parent 6b9e47a commit af44791
Show file tree
Hide file tree
Showing 28 changed files with 3,069 additions and 2 deletions.
188 changes: 188 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -717,3 +717,191 @@ const vpc = new VpcV2(this, 'VPC-integ-test-tag', {
// Add custom tags if needed
Tags.of(vpc).add('Environment', 'Production');
```

## Transit Gateway

The AWS Transit Gateway construct library allows you to create and configure Transit Gateway resources using AWS CDK.

See [AWS Transit Gateway Docs](docs.aws.amazon.com/vpc/latest/tgw/what-is-transit-gateway.html) for more info.

### Overview

The Transit Gateway construct (`TransitGateway`) is the main entry point for creating and managing your Transit Gateway infrastructure. It provides methods to create route tables, attach VPCs, and configure cross-account access.

The Transit Gateway construct library provides four main constructs:

- `TransitGateway`: The central hub for your network connections
- `TransitGatewayRouteTable`: Manages routing between attached networks
- `TransitGatewayVpcAttachment`: Connects VPCs to the Transit Gateway
- `TransitGatewayRoute`: Defines routing rules within your Transit Gateway

### Basic Usage

To create a minimal deployable `TransitGateway`:

```ts
const transitGateway = new TransitGateway(this, 'MyTransitGateway');
```

### Default Transit Gateway Route Table

By default, `TransitGateway` is created with a default `TransitGatewayRouteTable`, for which automatic Associations and automatic Propagations are enabled.

> Note: When you create a default Transit Gateway in AWS Console, a default Transit Gateway Route Table is automatically created by AWS. However, when using the CDK Transit Gateway L2 construct, the underlying L1 construct is configured with `defaultRouteTableAssociation` and `defaultRouteTablePropagation` explicitly disabled. This ensures that AWS does not create the default route table, allowing the CDK to define a custom default route table instead.
>
> As a result, in the AWS Console, the **Default association route table** and **Default propagation route table** settings will appear as disabled. Despite this, the CDK still provides automatic association and propagation functionality through its internal implementation, which can be controlled using the `defaultRouteTableAssociation` and `defaultRouteTablePropagation` properties within the CDK.

You can disable the automatic Association/Propagation on the default `TransitGatewayRouteTable` via the `TransitGateway` properties. This will still create a default route table for you:

```ts
const transitGateway = new TransitGateway(this, 'MyTransitGateway', {
defaultRouteTableAssociation: false,
defaultRouteTablePropagation: false,
});
```

### Transit Gateway Route Table Management

Add additional Transit Gateway Route Tables using the `addRouteTable()` method:

```ts
const transitGateway = new TransitGateway(this, 'MyTransitGateway');

const routeTable = transitGateway.addRouteTable('CustomRouteTable');
```

### Attaching VPCs to the Transit Gateway

Currently only VPC to Transit Gateway attachments are supported.

Create an attachment from a VPC to the Transit Gateway using the `attachVpc()` method:

```ts
const myVpc = new VpcV2(this, 'Vpc');
const subnet1 = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.0.0/24'),
subnetType: SubnetType.PUBLIC
});

const subnet2 = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.1.0/24'),
subnetType: SubnetType.PUBLIC
});

const transitGateway = new TransitGateway(this, 'MyTransitGateway');

// Create a basic attachment
const attachment = transitGateway.attachVpc('VpcAttachment', {
vpc: myVpc,
subnets: [subnet1, subnet2]
});

// Create an attachment with optional parameters
const attachmentWithOptions = transitGateway.attachVpc('VpcAttachmentWithOptions', {
vpc: myVpc,
subnets: [subnet1],
vpcAttachmentOptions: {
dnsSupport: true,
applianceModeSupport: true,
ipv6Support: true,
securityGroupReferencingSupport: true,
}
});
```

If you want to automatically associate and propagate routes with transit gateway route tables, you can pass the `associationRouteTable` and `propagationRouteTables` parameters. This will automatically create the necessary associations and propagations based on the provided route tables.

```ts
const myVpc = new VpcV2(this, 'Vpc');
const subnet1 = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.0.0/24'),
subnetType: SubnetType.PUBLIC
});

const subnet2 = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.1.0/24'),
subnetType: SubnetType.PUBLIC
});

const transitGateway = new TransitGateway(this, 'MyTransitGateway');
const associationRouteTable = transitGateway.addRouteTable('AssociationRouteTable');
const propagationRouteTable1 = transitGateway.addRouteTable('PropagationRouteTable1');
const propagationRouteTable2 = transitGateway.addRouteTable('PropagationRouteTable2');

// Create an attachment with automatically created association + propagations
const attachmentWithRoutes = transitGateway.attachVpc('VpcAttachment', {
vpc: myVpc,
subnets: [subnet1, subnet2],
associationRouteTable: associationRouteTable,
propagationRouteTables: [propagationRouteTable1, propagationRouteTable2],
});
```

In this example, the `associationRouteTable` is set to `associationRouteTable`, and `propagationRouteTables` is set to an array containing `propagationRouteTable1` and `propagationRouteTable2`. This triggers the automatic creation of route table associations and route propagations between the Transit Gateway and the specified route tables.

### Adding static routes to the route table

Add static routes using either the `addRoute()` method to add an active route or `addBlackholeRoute()` to add a blackhole route:

```ts
const transitGateway = new TransitGateway(this, 'MyTransitGateway');
const routeTable = transitGateway.addRouteTable('CustomRouteTable');

const myVpc = new VpcV2(this, 'Vpc');
const subnet = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.0.0/24'),
subnetType: SubnetType.PUBLIC
});

const attachment = transitGateway.attachVpc('VpcAttachment', {
vpc: myVpc,
subnets: [subnet]
});

// Add a static route to direct traffic
routeTable.addRoute('StaticRoute', attachment, '10.0.0.0/16');

// Block unwanted traffic with a blackhole route
routeTable.addBlackholeRoute('BlackholeRoute', '172.16.0.0/16');
```

### Route Table Associations and Propagations

Configure route table associations and enable route propagation:

```ts
const transitGateway = new TransitGateway(this, 'MyTransitGateway');
const routeTable = transitGateway.addRouteTable('CustomRouteTable');
const myVpc = new VpcV2(this, 'Vpc');
const subnet = new SubnetV2(this, 'Subnet', {
vpc: myVpc,
availabilityZone: 'eu-west-2a',
ipv4CidrBlock: new IpCidr('10.0.0.0/24'),
subnetType: SubnetType.PUBLIC
});
const attachment = transitGateway.attachVpc('VpcAttachment', {
vpc: myVpc,
subnets: [subnet]
});

// Associate an attachment with a route table
routeTable.addAssociation('Association', attachment);

// Enable route propagation for an attachment
routeTable.enablePropagation('Propagation', attachment);
```

**Associations** — The linking of a Transit Gateway attachment to a specific route table, which determines which routes that attachment will use for routing decisions.

**Propagation** — The automatic advertisement of routes from an attachment to a route table, allowing the route table to learn about available network destinations.
6 changes: 5 additions & 1 deletion packages/@aws-cdk/aws-ec2-alpha/awslint.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"exclude": [
"attribute-tag:@aws-cdk/aws-ec2-alpha.RouteTable.routeTableId",
"from-method:@aws-cdk/aws-ec2-alpha.Route"
"from-method:@aws-cdk/aws-ec2-alpha.Route",
"from-method:@aws-cdk/aws-ec2-alpha.TransitGateway",
"from-method:@aws-cdk/aws-ec2-alpha.TransitGatewayRouteTableAssociation",
"from-method:@aws-cdk/aws-ec2-alpha.TransitGatewayRouteTablePropagation",
"from-method:@aws-cdk/aws-ec2-alpha.TransitGatewayVpcAttachment"
]
}
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ export * from './ipam';
export * from './vpc-v2-base';
export * from './subnet-v2';
export * from './route';
export * from './transit-gateway';
export * from './transit-gateway-route';
export * from './transit-gateway-route-table';
export * from './transit-gateway-attachment';
export * from './transit-gateway-vpc-attachment';
export * from './transit-gateway-association';
export * from './transit-gateway-route-table-association';
export * from './transit-gateway-route-table-propagation';
20 changes: 20 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/transit-gateway-association.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IResource, Resource } from 'aws-cdk-lib/core';

/**
* Represents a Transit Gateway Route Table Association.
*/
export interface ITransitGatewayAssociation extends IResource {
/**
* The ID of the transit gateway route table association.
* @attribute
*/
readonly transitGatewayAssociationId: string;
}

/**
* A Transit Gateway Association.
* @internal
*/
export abstract class TransitGatewayAssociationBase extends Resource implements ITransitGatewayAssociation {
public abstract readonly transitGatewayAssociationId: string;
}
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-ec2-alpha/lib/transit-gateway-attachment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { IResource, Resource } from 'aws-cdk-lib/core';
/**
* Represents a Transit Gateway Attachment.
*/
export interface ITransitGatewayAttachment extends IResource {
/**
* The ID of the transit gateway attachment.
* @attribute
*/
readonly transitGatewayAttachmentId: string;
}

/**
* A Transit Gateway Attachment.
* @internal
*/
export abstract class TransitGatewayAttachmentBase extends Resource implements ITransitGatewayAttachment {
public abstract readonly transitGatewayAttachmentId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { ITransitGatewayAttachment } from './transit-gateway-attachment';
import { ITransitGatewayRouteTable } from './transit-gateway-route-table';
import { CfnTransitGatewayRouteTableAssociation } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
import { ITransitGatewayAssociation, TransitGatewayAssociationBase } from './transit-gateway-association';

/**
* Represents a Transit Gateway Route Table Association.
*/
export interface ITransitGatewayRouteTableAssociation extends ITransitGatewayAssociation {}

/**
* Common properties for a Transit Gateway Route Table Association.
*/
export interface TransitGatewayRouteTableAssociationProps {
/**
* The ID of the transit gateway route table association.
*/
readonly transitGatewayVpcAttachment: ITransitGatewayAttachment;

/**
* The ID of the transit gateway route table association.
*/
readonly transitGatewayRouteTable: ITransitGatewayRouteTable;

/**
* Physical name of this association.
*
* @default - Assigned by CloudFormation.
*/
readonly transitGatewayRouteTableAssociationName?: string;
}

/**
* Create a Transit Gateway Route Table Association.
*
* @resource AWS::EC2::TransitGatewayRouteTableAssociation
*/
export class TransitGatewayRouteTableAssociation extends TransitGatewayAssociationBase {
/**
* The ID of the transit gateway route table association.
*/
public readonly transitGatewayAssociationId: string;

constructor(scope: Construct, id: string, props: TransitGatewayRouteTableAssociationProps) {
super(scope, id);

const resource = new CfnTransitGatewayRouteTableAssociation(this, id, {
transitGatewayAttachmentId: props.transitGatewayVpcAttachment.transitGatewayAttachmentId,
transitGatewayRouteTableId: props.transitGatewayRouteTable.routeTableId,
});
this.node.defaultChild = resource;

this.transitGatewayAssociationId = resource.ref;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { IResource, Resource } from 'aws-cdk-lib/core';
import { CfnTransitGatewayRouteTablePropagation } from 'aws-cdk-lib/aws-ec2';
import { Construct } from 'constructs';
import { ITransitGatewayAttachment } from './transit-gateway-attachment';
import { ITransitGatewayRouteTable } from './transit-gateway-route-table';

/**
* Represents a Transit Gateway Route Table Propagation.
*/
export interface ITransitGatewayRouteTablePropagation extends IResource {
/**
* The ID of the transit gateway route table propagation.
* @attribute
*/
readonly transitGatewayRouteTablePropagationId: string;
}

/**
* Common properties for a Transit Gateway Route Table Propagation.
*/
export interface TransitGatewayRouteTablePropagationProps {
/**
* The ID of the transit gateway route table propagation.
*/
readonly transitGatewayVpcAttachment: ITransitGatewayAttachment;

/**
* The ID of the transit gateway route table propagation.
*/
readonly transitGatewayRouteTable: ITransitGatewayRouteTable;

/**
* Physical name of this propagation.
*
* @default - Assigned by CloudFormation.
*/
readonly transitGatewayRouteTablePropagationName?: string;
}

/**
* Create a Transit Gateway Route Table Propagation.
*
* @resource AWS::EC2::TransitGatewayRouteTablePropagation
*/
export class TransitGatewayRouteTablePropagation extends Resource implements ITransitGatewayRouteTablePropagation {
/**
* The ID of the transit gateway route table propagation.
*/
public readonly transitGatewayRouteTablePropagationId: string;

constructor(scope: Construct, id: string, props: TransitGatewayRouteTablePropagationProps) {
super(scope, id);

const resource = new CfnTransitGatewayRouteTablePropagation(this, id, {
transitGatewayAttachmentId: props.transitGatewayVpcAttachment.transitGatewayAttachmentId,
transitGatewayRouteTableId: props.transitGatewayRouteTable.routeTableId,
});
this.node.defaultChild = resource;

this.transitGatewayRouteTablePropagationId = resource.ref;
}
}
Loading

0 comments on commit af44791

Please sign in to comment.