Wie füge ich mit CloudFormation Routen zur Haupt-Routing-Tabelle in meiner VPC hinzu?

Lesedauer: 4 Minute
0

Ich möchte der Haupt-Routing-Tabelle Routen hinzufügen, wenn ich meine Amazon Virtual Private Cloud (Amazon VPC) in AWS CloudFormation erstelle.

Kurzbeschreibung

Wenn Sie CloudFormation verwenden, um eine Amazon VPC zu erstellen, erkennt CloudFormation die standardmäßig erstellte Haupt-Routing-Tabelle nicht. Daher können Informationen über die Routing-Tabelle nicht zwischen Ihrer Amazon VPC und CloudFormation ausgetauscht werden. Somit können Sie der Haupt-Routing-Tabelle keine Routen hinzufügen oder aus ihr entfernen, da Sie in Ihrer CloudFormation-Vorlage nicht auf die Routing-Tabelle verweisen können.

Lösung

Hinweis: Wenn Sie beim Ausführen von Befehlen der AWS Command Line Interface (AWS CLI) Fehler erhalten, stellen Sie sicher, dass Sie die neueste AWS CLI-Version verwenden.

Um dieses Problem zu lösen, können Sie eine AWS Lambda-unterstützte benutzerdefinierte Ressource in der CloudFormation-Vorlage verwenden. Der CloudFormation-Stack erstellt eine Amazon VPC. Anschließend verwendet die benutzerdefinierte Ressource eine AWS Lambda-Funktion, um die Haupt-Routing-Tabellen-ID abzurufen, die Ihrer Amazon VPC zugeordnet ist.

Erstellen Sie einen CloudFormation-Stack mithilfe der folgenden RouteTable-template.yml-Vorlage:

AWSTemplateFormatVersion: 2010-09-09
Description: Template to add routes to default/main routetable of VPC
Resources:
  MyVPC:
    Type: 'AWS::EC2::VPC'
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags:
        - Key: Env
          Value: Test
  LambdaIAMRole:
    Type: 'AWS::IAM::Role'
    DependsOn: MyVPC
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'ec2:Describe*'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'
  LambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaIAMRole.Arn
      Runtime: python3.9
      Timeout: 50
      Code:
        ZipFile: |
            from __future__ import print_function
            import json
            import boto3
            import urllib3
            import cfnresponse

            SUCCESS = "SUCCESS"
            FAILED = "FAILED"

            http = urllib3.PoolManager()

            print('Loading function')
            ec2 = boto3.client('ec2')

            def lambda_handler(event, context):
                print("Received event: " + json.dumps(event, indent=2))
                responseData={}
                try:
                    if event['RequestType'] == 'Delete':
                        print("Request Type:",event['RequestType'])
                        print("Delete Request - No Physical resources to delete")
                    elif event['RequestType'] == 'Create':
                        print("Request Type:",event['RequestType'])
                        VPCID=event['ResourceProperties']['VPCID']
                        RouteTableID=get_vpc(VPCID)
                        responseData={'RouteTableID':RouteTableID}
                        print("Sending response to custom resource")
                    elif event['RequestType'] == 'Update':
                        print("Request Type:",event['RequestType'])
                        VPCID=event['ResourceProperties']['VPCID']
                        RouteTableID=get_vpc(VPCID)
                        responseData={'RouteTableID':RouteTableID}
                        print("Sending response to custom resource")
                    responseStatus = 'SUCCESS'
                    print("responseStatus: " + responseStatus)
                    cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, "CustomResourcePhysicalID")
                except Exception as e:
                    print('Failed to process:', e)
                    responseStatus = 'FAILURE'
                    responseData = {'Failure': 'Something bad happened.'}
                    cfnresponse.send(event, context, cfnresponse.FAILURE, responseData, "CustomResourcePhysicalID")

            def get_vpc(VPCID):
                response = ec2.describe_route_tables (
                  Filters=[
                    {
                      'Name': 'association.main',
                      'Values': [ 'true' ]
                    },
                    {
                      'Name': 'vpc-id',
                      'Values': [ VPCID ]
                    }
                  ]
                )
                print("Printing the VPC Route Table ID ....")
                RouteTableID=response['RouteTables'][0]['RouteTableId']
                print(RouteTableID)
                return RouteTableID

            def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False):
                responseUrl = event['ResponseURL']
                print(responseUrl)
                responseBody = {'Status': responseStatus,
                                'Reason': 'See the details in CloudWatch Log Stream: ' + context.log_stream_name,
                                'PhysicalResourceId': physicalResourceId or context.log_stream_name,
                                'StackId': event['StackId'],
                                'RequestId': event['RequestId'],
                                'LogicalResourceId': event['LogicalResourceId'],
                                'Data': responseData}
                json_responseBody = json.dumps(responseBody)
                print("Response body:\n" + json_responseBody)
                headers = {
                    'content-type' : '',
                    'content-length' : str(len(json_responseBody))
                }
                try:
                    response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody)
                    print("Status code: " + response.reason)
                except Exception as e:
                    print("send(..) failed executing requests.put(..): " + str(e))


  Lambdatrigger:
    Type: 'Custom::RouteTableLambda'
    Properties:
      ServiceToken: !GetAtt LambdaFunction.Arn
      VPCID: !Ref MyVPC
  MyInternetGateway:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Env
          Value: Test
  AttachGateway:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    Properties:
      VpcId: !Ref MyVPC
      InternetGatewayId: !Ref MyInternetGateway
  MyRoute:
    Type: 'AWS::EC2::Route'
    Properties:
      RouteTableId: !GetAtt Lambdatrigger.RouteTableID

      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref MyInternetGateway
Outputs:
  RouteTableID:
    Value: !GetAtt Lambdatrigger.RouteTableID

Die Daten, die die benutzerdefinierte Ressource zurückgibt, enthalten die Haupt-Routing-Tabellen-ID. Sie können die ID mithilfe von GetAtt in AWS::EC2::Route referenzieren, um Routen zur Haupt-Routing-Tabelle hinzuzufügen. Außerdem zeigen die Ausgaben des Stacks die Routing-Tabellen-ID an.

Im Folgenden finden Sie ein Beispiel für den SUCCESS-Antworttext, den die benutzerdefinierte Ressource an den CloudFormation-Stack sendet:

{
  "Status": "SUCCESS",
  "Reason": "See the details in CloudWatch Log Stream: 2022/08/31/[$LATEST]c48b90efb3944c11ad3fb6e1ce5e1f45",
  "PhysicalResourceId": "CustomResourcePhysicalID",
  "StackId": "arn:aws:cloudformation:us-west-1:XXXX:stack/VPC-RT/06c957b0-297e-11ed-afb5-02ca6fd67f8d",
  "RequestId": "55c0f2b8-3044-47f7-aba4-84502b4ef632",
  "LogicalResourceId": "Lambdatrigger",
  "NoEcho": false,
  "Data": {
    "RouteTableID": "rtb-0fba8d15701234567a"
  }
}

AWS OFFICIAL
AWS OFFICIALAktualisiert vor 2 Jahren