This solution will provide an approach to automatically accept Transit Gateway attachments by checking a centrally managed list of allowed CIDR and AccountId value pairs when using a centralized Transit Gateway.
Prerequisite for this solution is the existence of a centralized Transit Gateway which is shared with all accounts via Resource Access Manager.
Problems when creating a Transit Gateway
When creating a Transit Gateway you are offered the option to AutoAcceptSharedAttachments
which means that if any account that uses the centralized Transit Gateway creates an attachment, it is automatically accepted.
Which in turn means that if we do not activate this feature we would have to manually accept all created Transit Gateway attachments. Depending on the size of your environment this could lead to a great overhead wasting valuable time resources.
Also probably not all created Transit Gateway Attachments are wanted but just a defined list of CIDR Blocks and Account IDs should be allowed to communicate with all VPCs and with the On-Premise datacenter.
So what if we just want an AutoAccept for specific CIDR blocks we defined prior? Then this solution will help you!
Overview over the Solution
This solution uses a DynamoDB table to manage the list of allowed CIDR Blocks and Account Ids pairs. Using cidr_block
as the primary key makes sure to not include the same CIDR Block multiple times in the Transit Gateway Attachments. As one account can include multiple VPCs with Transit Gateway attachments, setting it as the primary key wouldn't be suitable here.
The values of the DynamoDB Table are set in the code in a Custom Resource which is used to initialize the DynamoDB Table. The Custom Resource executes a Lambda function during deployment or when the stack changes and creates the values for the DynamoDB Table which are documented in the code.
Also in every account an EventBridge Rule gets created which sends an event to the default base as soon as it captures the CloudTrail event CreateTransitGatewayVpcAttachment
. The default bus of the corresponding account sends the event to the account where the Transit Gateway is created and triggers an Eventbridge Rule there which executes a Lambda Function.
As well a cross-account Lambda Role gets created in every account to read-out the CIDR Block of the VPC mentioned in the event.
The Lambda function then checks if an entry for the provided CIDR Block and Account Id exists in the DynamoDB table and accepts the Attachment when a match is found.
Deployment Steps
The solutions consists of two stacks.
The tgw-attach-auto-accept-core.yaml
file needs to be created in the Account where the Transit Gateway is located.
The following resources will be created in the first stack:
A DynamoDB Table for the entries of allowed CIDR Blocks and Account Ids. The CIDR Block functions as the primary key.
TGWAttachmentDynamoDB:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: 'TGWAttachmentAcceptedCIDR'
AttributeDefinitions:
- AttributeName: 'cidr_block'
AttributeType: 'S'
- AttributeName: 'account_id'
AttributeType: 'S'
KeySchema:
- AttributeName: 'cidr_block'
KeyType: 'HASH'
- AttributeName: 'account_id'
KeyType: 'RANGE'
BillingMode: PAY_PER_REQUEST
A Custom Resources to initialize the DynamoDB Table entries and set the values. Every time the list of values in the Custom Resource gets updated, the Lambda Function will be executed again to update the DynamoDB Table.
DynamoDBTableInitializer:
Type: Custom::DynamoDBTableInitializer
Properties:
ServiceToken: !GetAtt TableInitializerFunction.Arn
TableName: !Ref TGWAttachmentDynamoDB
TableItems:
- cidr_block: "1.2.3.4/5"
account_id: "123456789012"
- cidr_block: "6.7.8.9/12"
account_id: "234567890123"
### more entries can be added here
TableInitializerFunction:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
import json
import boto3
import cfnresponse
def lambda_handler(event, context):
try:
table_name = event['ResourceProperties']['TableName']
items = event['ResourceProperties']['TableItems']
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(table_name)
for item in items:
table.put_item(Item=item)
response_data = {'Status': 'Success'}
cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
except Exception as e:
response_data = {'Status': str(e)}
cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
Handler: 'index.lambda_handler'
Runtime: python3.11
Role: !GetAtt TableInitializerFunctionRole.Arn
An Eventbridge Rule which receives the "CreateTransitGatewayVpcAttachment" event from the default bus and triggers the Lambda function to check and accept the attachment.
CloudWatchRule:
Type: "AWS::Events::Rule"
Properties:
Description: "Accepts the TGW Attachment and sets a Route in the Route Table to OnP-remise"
State: ENABLED
EventPattern: {
"source": [
"aws.ec2"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"ec2.amazonaws.com"
],
"eventName": [
"CreateTransitGatewayVpcAttachment"
]
}
}
Name: TGWAcceptAutoAttach
Targets:
- Arn: !GetAtt LambdaFunction.Arn
Id: LambdaFunction
A Lambda Function to check the source account which created the attachment, read out the DynamoDB table and if required accept the Transit Gateway Attachment (code in Github).
After that the tgw-attach-auto-accept-global.yaml
needs to be executed in all accounts, deploying it as a Stackset is recommended. This will create the following resources:
An Eventbridge Rule to capture CreateTransitGatewayVpcAttachment
CloudTrail events from the specific accounts.
TGWAttachAutoAcceptRule:
Type: "AWS::Events::Rule"
Condition: IsNotTGWAccount
Properties:
Description: CloudWatch Event Rule for automatically accepting TGW Attachments
EventPattern: {
"source": [
"aws.ec2"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"ec2.amazonaws.com"
],
"eventName": [
"CreateTransitGatewayVpcAttachment"
]
}
}
Name: "RuleForTGWAttachAutoAccept"
Targets:
- Arn: !Sub "arn:aws:events:${AWS::Region}:${TgwAccount}:event-bus/default"
Id: "TGWAttachAutoAcceptRule"
RoleArn: !GetAtt TGWAttachAutoAcceptRole.Arn
A Cross-Account IAM Role to read-out the CIDR Block from the corresponding VPC which is given in the event
CrossAccountLambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: CrossAccountLambdaRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub 'arn:aws:iam::${TgwAccount}:root'
Action:
- sts:AssumeRole
MaxSessionDuration: 3600
Path: /
Policies:
- PolicyName: CrossAccountLambdaRolePolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- ec2:DescribeVpcs
Resource: "*"
- Effect: Allow
Action:
- iam:PassRole
Resource: 'arn:aws:iam::*:role/*'
After the successful deployment and adding the relevant CIDR Block and Account Id pairs, you should be able to see the Transitgateway Attachment gets enabled automatically!
The complete solution is accessible in Github.
About PCG
Public Cloud Group supports companies in their digital transformation through the use of public cloud solutions.
With a product portfolio designed to accompany organisations of all sizes in their cloud journey and competence that is a synonym for highly qualified staff that clients and partners like to work with, PCG is positioned as a reliable and trustworthy partner for the hyperscalers, relevant and with repeatedly validated competence and credibility.
We have the highest partnership status with the three relevant hyperscalers: Amazon Web Services (AWS), Google, and Microsoft. As experienced providers, we advise our customers independently with cloud implementation, application development, and managed services.
Top comments (0)