How to get Subnet's associated Route Table ID in Cloud​Formation?

0

My CloudFormation template includes creation of an S3 AWS::EC2::VPCEndpoint. In parameters, users select an already-created VPC, Subnet, and AZ. One of the required parameters for S3 endpoint is Route Table Id. For now, I have it set to request a String of Route Table ID ("rtb-xxxxxx") but would like to simplify it for the user by getting it programmatically.

The question is, how can I instead get a Route Table ID based on selected Subnet ID? AWS::EC2::Subnet does not support return value for Route Table ID associated with it. I know that I could also do that by calling a Lambda but I was hoping to find a more native solution.

The Route Table ID I am looking for is NOT VPC's Main route table.

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-subnet.html

1 Antwort
0
Akzeptierte Antwort

Custom Resource (or Macro) is the only way to go. Not only does AWS::EC2::Subnet not support it as a return value as you mentioned, but you're also trying to reference an existing resource not created by your template.


Quick sample but do note - DescribeRouteTables will only work if the subnet has been explicitly associated and not for a default route table. That will require extra coding/logic.

AWSTemplateFormatVersion: "2010-09-09"
Description: Subnet Custom Resource
Parameters: 
  TheSubnet:
    Description: Subnet ID
    Type: AWS::EC2::Subnet::Id
    Default: subnet-32432943294

Resources:
  CustomFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Timeout: 30
      Role: !GetAtt 'CustomResourceRole.Arn'
      Runtime: python3.7
      Code:
        ZipFile: |
          import boto3
          import json
          import urllib

          def sendResponse(event, context, responseData, responseStatus="FAILED"):
            response_body = json.dumps({
              "Status": responseStatus,
              "Reason": "See the details in CloudWatch Log Stream: " + context.log_stream_name,
              "PhysicalResourceId": context.log_stream_name,
              "StackId": event["StackId"],
              "RequestId": event["RequestId"],
              "LogicalResourceId": event["LogicalResourceId"],
              "Data":responseData
            })

            # Not using the old .put (deprecated)
            enc_body = response_body.encode('utf-8')
            opener = urllib.request.build_opener(urllib.request.HTTPHandler)
            request = urllib.request.Request(event['ResponseURL'], data=enc_body)
            request.add_header('Content-Type', '')
            request.add_header('Content-Length', len(response_body))
            request.get_method = lambda: 'PUT'
            response = opener.open(request)
            print("RESPONSE {}: {}".format(response.getcode(), response.msg))


          def lambda_handler(event, context):
            # Delete...
            if event['RequestType'] == 'Delete':
              sendResponse(event, context, {"Message": "DELETE"}, "SUCCESS")
              return '{}'
            
            try:
              ec2 = boto3.client('ec2')
              subnet = event["ResourceProperties"].get("SubnetId")
              resp = ec2.describe_route_tables(
                Filters=
                  [
                    {
                      'Name': 'association.subnet-id',
                      'Values': [subnet]
                    }
                  ]
              )
              print(resp['RouteTables'][0])
              sendResponse(event, context, resp['RouteTables'][0], "SUCCESS")
            except:
              print("ERROR")
              sendResponse(event, context, {"Value": "ERROR"})

  CustomResourceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
          Condition: {}
      Path: /
      Policies:
        - PolicyName: QuerySubnet
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
              - Effect: Allow
                Action:
                  - ec2:DescribeSubnets
                  - ec2:DescribeRouteTables
                Resource: '*'
  
  SubnetQuery:
    Type: Custom::CustomResource
    Properties:
      ServiceToken: !GetAtt CustomFunction.Arn
      SubnetId: !Ref TheSubnet

Outputs:
  RouteTableId:
    Description: Discovered Route Table ID
    Value: !GetAtt SubnetQuery.RouteTableId
AWS
EXPERTE
Raphael
beantwortet vor 4 Jahren

Du bist nicht angemeldet. Anmelden um eine Antwort zu veröffentlichen.

Eine gute Antwort beantwortet die Frage klar, gibt konstruktives Feedback und fördert die berufliche Weiterentwicklung des Fragenstellers.

Richtlinien für die Beantwortung von Fragen