Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
954 views
in Technique[技术] by (71.8m points)

amazon web services - AWS: Why I am unable to assign a custom domain to the nested stack?

I am trying to integrate a custom domain to the HTTP API I am developing with AWS API Gateway and AWS Lambda. I m using the AWS SAM template. There I have a root stack and nested stacks.

For this question I will use a code piece with a one nested stack. There, this is how I want the URL end points to be

  1. root stack - api.example.com
  2. nested stack - api.example.com/nested

Below is my code

Root stack

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-restapi

  Sample SAM Template for aws-restapi
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 5
    VpcConfig:
        SecurityGroupIds:
          - sg-041f24xxxx921e8e
        SubnetIds:
          - subnet-0xxxxx2d


Parameters:
  FirebaseProjectId:
    Type: String
  
  #Dont create this domain in the AWS Console manually, so it will fail here
  DomainName:
    Type: String
    Default: api.example.com

Resources:
  AuthGatewayHttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      Domain:
        DomainName: !Ref DomainName
        EndpointConfiguration: REGIONAL
        CertificateArn: arn:aws:acm:us-east-1:xxxx:certificate/xxxx-420d-xxxx-b40d-xxxx
        Route53:
          HostedZoneId: xxxxxxxxxxx
      Auth:
        Authorizers:
          FirebaseAuthorizer:
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              audience:
                - !Ref FirebaseProjectId
              issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
        DefaultAuthorizer: FirebaseAuthorizer

 
  AuthFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: aws-restapi/
      Handler: source/testfile.lambdaHandler
      Runtime: nodejs14.x
      Events:
        Gateway:
          Type: HttpApi
          Properties:
            ApiId: !Ref AuthGatewayHttpApi
            Path: /hello
            Method: get

  NestedStackTwo:
    DependsOn: AuthGatewayHttpApi
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: nested_stack.yaml
      Parameters:
        FirebaseProjectId: !Ref FirebaseProjectId
        DomainName: !Ref DomainName

Nested stack

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-restapi

  Sample SAM Template for aws-restapi

Globals:
  Function:
    Timeout: 5
    VpcConfig:
        SecurityGroupIds:
          - sg-xxxxxxxxxxxx
        SubnetIds:
          - subnet-xxxxxxxxxxx

Parameters:
  FirebaseProjectId:
    Type: String
  
  DomainName:
    Type: String

Resources:

  AuthGatewayHttpApi2:
    Type: AWS::Serverless::HttpApi
    Properties:
      Domain:
        DomainName: !Ref DomainName
        BasePath: two
        EndpointConfiguration: REGIONAL
        CertificateArn: arn:aws:acm:us-east-1:xxxxx:certificate/xxxxx-xxxx-xxxx-xxxx-xxxx
        Route53:
          HostedZoneId: xxxxxxxxxxxxx
      Auth:
        Authorizers:
          FirebaseAuthorizer:
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              audience:
                - !Ref FirebaseProjectId
              issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
        DefaultAuthorizer: FirebaseAuthorizer

  GetAllPromotionsFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: aws-restapi/
      Handler: source/promotions/promotions-getall.getAllPromotions
      Runtime: nodejs14.x
      Events:
        GetAllPromotionsAPIEvent:
          Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /promotions/getall
            Method: get
            ApiId: !Ref AuthGatewayHttpApi2
  

However I cant get this to work because the nested stack fails to create. Below is the error

CREATE_FAILED                      AWS::CloudFormation::Stack         NestedStackTwo
                                                    

Embedded stack arn:aws:cloudformation:us-east-1 xxxxx:stack/aws-restapi-NestedStackTwo-8KBISZRAVYBX/a3fcc010-0ce4-11ec-9c90-0e8a861a6983 was not successfully created:

 The following resource(s) failed to create: [ApiGatewayDomainNameV234ac706a57] 

I believe this is happening because the root stack creates the domain and the nested stack is trying to re-create it instead of reusing the same.

But, here is the fun fact; if i use the AWS API GATEWAY web console, I can do this in no time.

How can I get this to work in aws-sam ?

UPDATE

Following the advice from the user LRutten, I came up with the following code for the nested stack.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  aws-restapi

  Sample SAM Template for aws-restapi

Globals:
  Function:
    Timeout: 5
    VpcConfig:
        SecurityGroupIds:
          - sg-xxxxxx
        SubnetIds:
          - subnet-xxxxx

Parameters:
  FirebaseProjectId:
    Type: String
  
  DomainName:
    Type: String

Resources:

  AuthGatewayHttpApi2:
    Type: AWS::Serverless::HttpApi
    Properties:
      Auth:
        Authorizers:
          FirebaseAuthorizer:
            IdentitySource: $request.header.Authorization
            JwtConfiguration:
              audience:
                - !Ref FirebaseProjectId
              issuer: !Sub https://securetoken.google.com/${FirebaseProjectId}
        DefaultAuthorizer: FirebaseAuthorizer
  
  MyApiMapping:
    Type: 'AWS::ApiGatewayV2::ApiMapping'
    Properties:
      DomainName: !Ref DomainName
      ApiId: !Ref AuthGatewayHttpApi2
      Stage: prod
  
  MyDomainName:
    Type: 'AWS::ApiGatewayV2::DomainName'
    Properties:
      DomainName: !Ref DomainName
      DomainNameConfigurations:
        - EndpointType: REGIONAL
          CertificateArn: arn:aws:acm:us-east-1:716460586643:certificate/bac44716-420d-431b-b40d-01378f20432d


  GetAllPromotionsFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: aws-restapi/
      Handler: source/promotions/promotions-getall.getAllPromotions
      Runtime: nodejs14.x
      Events:
        GetAllPromotionsAPIEvent:
          Type: HttpApi # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /promotions/getall
            Method: get
            ApiId: !Ref AuthGatewayHttpApi2

This ended up with the following error

Embedded stack arn:aws:cloudformation:us-east-1:716460586643:stack/aws-restapi-NestedStackTwo-14SAYLRO1WD1D/62336020-xx-xx-a04e-x was not successfully created:

The following resource(s) failed to create: [MyDomainName, MyApiMapping]. 
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Indeed SAM always creates the domain when you specify it's name there. It stated in the docs as well.

To get around this, you can omit the whole domain configuration in the AWS::Serverless::HttpApi resource and write the resources created by SAM yourself. So add a section with

Type: AWS::ApiGatewayV2::ApiMapping
Properties: 
  ApiId: String
  ApiMappingKey: String
  DomainName: String
  Stage: String

Docs

Make sure the Stage property in the ApiMapping is also present in the StageName property of the API.

And a

Type: AWS::ApiGatewayV2::DomainName
Properties: 
  DomainName: String
  DomainNameConfigurations: 
    - DomainNameConfiguration
  MutualTlsAuthentication: 
    MutualTlsAuthentication
  Tags: Json

Docs

Manually adding these without having the domain itself defined twice should do the trick.

Edit: woops wasn't really thinking straight. You should of course only have the mapping, not the domain name itself again :P.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...