amazon-web-servicesaws-api-gatewayaws-cloudformationserverless-frameworkregional

How to get the target domain name of a custom domain for Regional AWS API Gateway in Cloudformation?


I'm trying to create a multi-region serverless application on AWS. I've followed the instructions given here. I'm using Serverless framework, which uses Cloudformation scripts for creating all the resources on AWS.

I want to create a custom domain for API gateway as a Regional Endpoint. When it creates a Regional endpoint, it generates a target domain. I would like to know how can I get the value of the target domain in my Cloudformation script?

When I create an Edge optimized Endpoint, I get the value of the CloudFront deployment by using the DistributionDomainName attribute. But I don't see any attribute for the target domain name when a Regional Endpoint is created. I tried using the DistributionDomainName attribute for a Regional endpoint, but it throws an error which says that there is no DistributionDomainName.

Below is a part of my script -

# Creates a custom domain for the ApiGateway
customDomain:
  Type: 'AWS::ApiGateway::DomainName'
  Properties:
    DomainName: ${self:custom.domain}
    EndpointConfiguration:
      Types:
        - REGIONAL
    RegionalCertificateArn: ${self:custom.certificateArn}

# Insert a DNS record in route53 hosted zone to redirect from the custom domain to CF distribution
dnsRecord:
  Type: AWS::Route53::RecordSet
  Properties:
    Region: ${self:provider.region}
    SetIdentifier: ${self:provider.region}
    HostedZoneId: ${self:custom.hostedZoneId}
    Name: ${self:custom.domain}
    Type: CNAME
    TTL: 60
    ResourceRecords:
      - "Fn::GetAtt": [customDomain, DistributionDomainName]

Please help. Thanks!

UPDATE

Cloudformation now returns the regional domain name through RegionalDomainName property. It could be used as Fn:GetAtt : [customDomain, RegionalDomainName].


Solution

  • This is not possible at the moment.

    As you mentioned, the only exposed parameter is DistributionDomainName and this works only for edge-optimized endpoints.

    As a workaround (until it will be implemented in CloudFormation) you could use a CustomResource backed up by your own Lambda function to return the regionalDomainName attribute.

    Here's a sample CloudFormation YAML code that does this:

    Resources:
      # The workaround Lambda that returns the regionalDomainName property
      RegionalDomainLambda:
        Type: AWS::Lambda::Function
        Properties:
          Runtime: python2.7
          Handler: index.handler
          Role:
            'Fn::GetAtt': [YOUR_ROLE_GOES_HERE, Arn] # make sure you include apigateway:GET
          Timeout: 50
          Code:
            ZipFile: |
              import cfnresponse
              import json
              import boto3
    
              client = boto3.client('apigateway')
              def handler(event, context):
                  response_data = {}
                  try:
                      domainName = event['ResourceProperties']['DomainName']
                      regional_domain_name = client.get_domain_name(domainName=domainName)['regionalDomainName']
                      response_data['value'] = regional_domain_name
    
                      cfnresponse.send(event, context, cfnresponse.SUCCESS,response_data, "RegionalDomainNameString")
                  except Exception as e:
                      response_data['exception'] = e
                      cfnresponse.send(event, context, cfnresponse.FAILED, response_data, "RegionalDomainNameString")
    
      # The resource that serves as a placeholder
      RegionalDomain:
        Type: Custom::CustomResource
        Properties:
          ServiceToken:
            'Fn::GetAtt': [RegionalDomainLambda, Arn]
          DomainName: {Ref: YOUR_API_GATEWAY_DOMAIN_NAME_GOES_HERE}
    
      # And here's how to use it
      SomeOtherResource:
        SomeOtherProperty: {'Fn::GetAtt': [RegionalDomain, value]}