Services or capabilities described in AWS documentation might vary by Region. To see the differences applicable to the AWS European Sovereign Cloud Region, see the AWS European Sovereign Cloud User Guide.Automate the setup of inter-Region peering with AWS Transit Gateway
Ram Kandaswamy, Amazon Web Services
Summary
AWS Transit Gateway connects virtual private clouds (VPCs) and on-premises networks through a central hub. Transit Gateway traffic doesn't traverse the public internet, which reduces threat vectors, such as common exploits and distributed denial of service (DDoS) attacks.
If you need to communicate between two or more AWS Regions, you can use inter-Region Transit Gateway peering to establish peering connections between transit gateways in different Regions. However, manually configuring inter-Region peering with Transit Gateway can be a complex and time-consuming. This pattern provides guidance for using infrastructure as code (IaC) to set up peering. You can use this approach if you have to repeatedly configure several Regions and AWS accounts for a multi-Region organization setup.
This pattern sets up an AWS CloudFormationstack that includes an AWS Step Functions workflow, AWS Lambda functions, AWS Identity and Access Management (IAM) roles, and log groups in Amazon CloudWatch Logs. You then run the Step Functions workflow to create the inter-Region peering connection for your transit gateways.
Prerequisites and limitations
Prerequisites
An active AWS account.
An IDE that has code-generation capability, such as Kiro.
An Amazon Simple Storage Service (Amazon S3) bucket and permissions to upload objects to it.
Transit gateways created in the requesting and accepting Regions.
VPCs created in the requesting and accepting Regions. Tag the VPCs with an addToTransitGateway key with a value of true.
Security groups configured for your VPCs according to your requirements.
Network access control lists (ACLs) configured for your VPCs according to your requirements.
Limitations
Architecture
The agentic AI development approach described in this pattern involves the following steps:
Define the automation prompt – Kiro receives a natural language prompt that details the peering requirements.
Generate automation script – Kiro generates the CloudFormation and Lambda scripts based on the provided prompt.
Deploy the stack – Kiro uses CloudFormation to deploy the required resources.
Set up peering – Kiro runs the Step Functions workflow, which calls Lambda functions to create peering connections and modify route tables.
The following diagram shows the Step Functions workflow:
The workflow contains the following steps:
The Step Functions workflow calls the Lambda function for the Transit Gateway peering.
The workflow waits for one minute.
The workflow retrieves the peering status and sends it to the condition block. The block is responsible for the looping.
If the success condition is not met, the workflow is coded to enter the timer stage.
If the success condition is met, a Lambda function modifies the route tables.
The Step Functions workflow ends.
AWS CloudFormation helps you set up AWS resources, provision them quickly and consistently, and manage them throughout their lifecycle across AWS accounts and AWS Regions.
Amazon CloudWatch Logs helps you centralize the logs from all your systems, applications, and AWS services so you can monitor them and archive them securely.
AWS Identity and Access Management (IAM) helps you securely manage access to your AWS resources by controlling who is authenticated and authorized to use them.
Kiro is an agentic AI development tool that helps you build production-ready applications through spec-driven development.
AWS Lambda is a compute service that helps you run code without needing to provision or manage servers. It runs your code only when needed and scales automatically, so you pay only for the compute time that you use.
AWS Step Functions is a serverless orchestration service that helps you combine AWS Lambda functions and other AWS services to build business-critical applications.
Epics
| Task | Description | Skills required |
|---|
Filling prompt placeholders with specific details | Update the following prompt by replacing the AWS Regions and bucket names: - Active region: ACTIVE_REGION
- Passive region: PASSIVE_REGION
- S3_BUCKET : my-lambda-packages-bucket
- STACK_NAME : transit-gateway-peering
- All Lambda functions use two boto3 EC2 clients at module level (one per region), each with signature_version v4 and retries max_attempts=1 mode=standard.
- Print all API responses for CloudWatch logging.
Save this as a markdown file. Add this markdown file to your Kiro project for context.
Alternatively, you can add this as an inline prompt that references the above variables without attaching the file for context. | General AWS, Network administrator |
Create a Lambda function that creates the peering attachments. | In your Kiro project, enter the following prompt: Write a Python Lambda that creates a transit gateway peering attachment from active region to passive region. Both of these regions will be read as environment variables of the Lambda function. Use two boto3 EC2 clients at the module level, one per Region. The handler should describe available transit gateways in both Regions. Then check if a peering attachment already exists on the active side by filtering describe_transit_gateway_attachments for resource-type "peering" and states: available, initiatingRequest, modifying, pendingAcceptance, pending, rejected, and rejecting. Only if zero results, create the peering attachment with tags for both Transit Gateway IDs, then wait 60 seconds (AWS needs this before the passive side can accept), then call accept_transit_gateway_peering_attachment on the passive client. Print all API responses.
Save and name this file peer-transit-gateway.py.
| General AWS, Network administrator, Prompt engineering |
Create a Lambda function that polls the peering attachment status. | In your Kiro project, enter the following prompt: Using the shared context above, write a Python Lambda that polls peering attachment status. Describe available transit gateways in both regions, then call describe_transit_gateway_attachments on the active client filtered by the active Transit Gateway ID only (no resource-type filter). Return exactly `{'status': status}` where status is the State field from the first attachment. Do not return statusCode or body — the Step Function Choice state reads `$.Payload.status` and compares to "available".
Save and name this file get-transit-gateway-peering-status.py.
| General AWS, Network administrator, Prompt engineering |
Create a Lambda function that adds static routes to both Regions. | In your Kiro project, enter the following prompt: Using the shared context, write a Python Lambda that adds static routes to both regions' TGW route tables. Describe available transit gateways in both Regions, extract each transit gateway's AssociationDefaultRouteTableId. Discover routable VPCs by filtering describe_vpcs with tag `addtotransitgateway=true` in each region, collecting their CIDRs. Get the peering attachment ID from the active side by filtering on the active route table ID. For each passive CIDR, search the active route table using `route-search.exact-match` — only create the route if none found. For each active CIDR, search the passive route table using `route-search.supernet-of-match` (not exact-match — passive side may have supernet routes) — only create if none found. Both sides use the same peering attachment ID.
Save and name this file as modify-transit-gateway-routes.py.
| General AWS, Network administrator |
Create the CloudFormation template. | Enter the following orchestration prompt, which creates a CloudFormation template: Write a CloudFormation JSON template that deploys: three Lambda functions (peer-transit-gateway with 600s timeout, get-transit-gateway-peering-status with 30s timeout, modify-transit-gateway-routes with 600s timeout), Lambda code from an S3 bucket parameter (no default value — user must supply the bucket name at deploy time), a Step Functions state machine, and CloudWatch log groups with 90-day retention. The state machine flow is:
1. Invoke peer-transit-gateway
2. Wait 20 seconds (attachment needs time after the Lambda's internal 20s sleep + acceptance)
3. Invoke get-transit-gateway-peering-status
4. Choice: if `$.Payload.status` equals "available" → go to step 5, otherwise loop back to step 2
5. Invoke modify-transit-gateway-routes → End
Use `Fn::Sub` with Lambda ARN references like `${PeerTransitGateways.Arn}` in the DefinitionString. The polling loop has no max retry — it loops until "available" (typically 3-5 minutes total).
Save and name the file transit-gateway-peering.json.
| AWS DevOps, General AWS, Prompt engineering |
| Task | Description | Skills required |
|---|
Deploy the CloudFormation stack by using prompts. | Enter the following prompt: Using the outputs from Prompts 1-4, package and deploy the full stack. Steps:
1. For each of the three Python files from Prompts 1-3, create a zip named after the file (e.g. peer-transit-gateway.zip that contains peer-transit-gateway.py).
2. Upload all three zips to S3_BUCKET.
3. Deploy the CloudFormation template from Prompt 4 to ACTIVE_REGION with S3BucketName=S3_BUCKET and CAPABILITY_NAMED_IAM.
4. Initiate the Step Function from the deployed stack.
Zip file names must match the S3Key values in the template exactly.
| AWS DevOps, Cloud administrator, General AWS, Prompt engineering |
Validate deployment. | | General AWS |
Related resources