amazon-web-services - 将 Route53 记录集正确的 CloudFormation 发送到 API 网关

标签 amazon-web-services aws-cloudformation aws-api-gateway aws-cli

我正在尝试部署一个 CloudFormation 模板(通过 AWS CLI),其中包含 DynamoDB 和一些通过 API Gateway 提供服务的 Lambda。模板如下:

Resources:
  UTableArticle:
    Type: AWS::DynamoDB::Table
    Properties:
      KeySchema:
        - AttributeName: id
          KeyType: HASH
      AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
      TableName: !Sub ${AWS::StackName}-Article
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
  UIAMRoleFunctionServiceRoleArticle:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'

  UIAMRoleFunctionServiceRolePolicyArticle:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action:
              - dynamodb:BatchGetItem
              - dynamodb:GetRecords
              - dynamodb:GetShardIterator
              - dynamodb:Query
              - dynamodb:GetItem
              - dynamodb:Scan
              - dynamodb:BatchWriteItem
              - dynamodb:PutItem
              - dynamodb:UpdateItem
              - dynamodb:DeleteItem
            Effect: Allow
            Resource:
              - !GetAtt [ UTableArticle, Arn ]
              - !Ref AWS::NoValue
        Version: "2012-10-17"
      PolicyName: UIAMRoleFunctionServiceRolePolicyArticle
      Roles:
        - !Ref UIAMRoleFunctionServiceRoleArticle

  BFunctionSaveArticle:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref ArtefactRepositoryBucket
        S3Key: !Join [ '', [!Ref ArtefactRepositoryKeyPrefix, '.zip' ] ]
      Handler: !Ref 'SaveArticleHandler'
      Role: !GetAtt [ UIAMRoleFunctionServiceRoleArticle, Arn ]
      Runtime: java11
      Environment:
        Variables:
          TABLE_NAME: !Ref UTableArticle
          PRIMARY_KEY: id
    DependsOn:
      - UIAMRoleFunctionServiceRolePolicyArticle
      - UIAMRoleFunctionServiceRoleArticle
  BFunctionGetArticle:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref ArtefactRepositoryBucket
        S3Key: !Join [ '', [!Ref ArtefactRepositoryKeyPrefix, '.zip' ] ]
      Handler: !Ref 'GetArticleHandler'
      Role: !GetAtt [ UIAMRoleFunctionServiceRoleArticle, Arn ]
      Runtime: java11
      Environment:
        Variables:
          TABLE_NAME: !Ref UTableArticle
          PRIMARY_KEY: id
    DependsOn:
      - UIAMRoleFunctionServiceRolePolicyArticle
      - UIAMRoleFunctionServiceRoleArticle
  BFunctionListArticles:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Ref ArtefactRepositoryBucket
        S3Key: !Join [ '', [!Ref ArtefactRepositoryKeyPrefix, '.zip' ] ]
      Handler: !Ref 'ListArticlesHandler'
      Role: !GetAtt [ UIAMRoleFunctionServiceRoleArticle, Arn ]
      Runtime: java11
      Environment:
        Variables:
          TABLE_NAME: !Ref UTableArticle
          PRIMARY_KEY: id
    DependsOn:
      - UIAMRoleFunctionServiceRolePolicyArticle
      - UIAMRoleFunctionServiceRoleArticle

  BFunctionGWPermissionGetArticle:
    Type: AWS::Lambda::Permission
    DependsOn:
      - BlogRestApi
      - BFunctionListArticles
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt [ BFunctionListArticles, Arn ]
      Principal: apigateway.amazonaws.com
      SourceArn: !Join ['', ['arn:', !Ref 'AWS::Partition', ':execute-api:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref BlogRestApi, '/*/GET/article'] ]
  BFunctionGWPermissionPostArticle:
    Type: AWS::Lambda::Permission
    DependsOn:
      - BlogRestApi
      - BFunctionSaveArticle
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt [ BFunctionSaveArticle, Arn ]
      Principal: apigateway.amazonaws.com
      SourceArn: !Join ['', ['arn:', !Ref 'AWS::Partition', ':execute-api:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref BlogRestApi, '/*/POST/article'] ]
  BFunctionGWPermissionGetIdArticle:
    Type: AWS::Lambda::Permission
    DependsOn:
      - BlogRestApi
      - BFunctionGetArticle
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt [ BFunctionGetArticle, Arn ]
      Principal: apigateway.amazonaws.com
      SourceArn: !Join ['', ['arn:', !Ref 'AWS::Partition', ':execute-api:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref BlogRestApi, '/*/GET/article/{id}'] ]
  BFunctionGWPermissionPatchIdArticle:
    Type: AWS::Lambda::Permission
    DependsOn:
      - BlogRestApi
      - BFunctionSaveArticle
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt [ BFunctionSaveArticle, Arn ]
      Principal: apigateway.amazonaws.com
      SourceArn: !Join ['', ['arn:', !Ref 'AWS::Partition', ':execute-api:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref BlogRestApi, '/*/PATCH/article/{id}'] ]
  BlogRestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: Article
  UAGDeploymentArticle:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref BlogRestApi
      Description: Automatically created by the RestApi construct
    DependsOn:
      - UAGMethodArticleIdGet
      - UAGMethodArticleIdPatch
      - UAGResourceArticleId
      - UAGMethodArticleGet
      - UAGMethodArticlePost
      - UAGResourceArticle
  BAGDeploymentStageProdArticle:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId: !Ref BlogRestApi
      DeploymentId: !Ref UAGDeploymentArticle
      StageName: prod
  UAIMRoleCWPushArticle:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: !Join ["", ['apigateway.', !Ref "AWS::URLSuffix"] ]
        Version: "2012-10-17"
      ManagedPolicyArns:
        - !Join ['', ['arn:', !Ref 'AWS::Partition', ':iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs'] ]
  UAGAccountArticle:
    Type: AWS::ApiGateway::Account
    Properties:
      CloudWatchRoleArn: !GetAtt [ UAIMRoleCWPushArticle, Arn ]
    DependsOn:
      - BlogRestApi
  UAGResourceArticle:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !GetAtt [ BlogRestApi, RootResourceId ]
      PathPart: article
      RestApiId: !Ref BlogRestApi
  UAGMethodArticleGet:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: GET
      ResourceId: !Ref UAGResourceArticle
      RestApiId: !Ref BlogRestApi
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Join [ "", ['arn:', !Ref 'AWS::Partition', ':apigateway:', !Ref 'AWS::Region', ':lambda:path/2015-03-31/functions/', !GetAtt [ BFunctionListArticles, Arn ], '/invocations' ] ]
  UAGMethodArticlePost:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST
      ResourceId: !Ref UAGResourceArticle
      RestApiId: !Ref BlogRestApi
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Join [ "", ['arn:', !Ref 'AWS::Partition', ':apigateway:', !Ref 'AWS::Region', ':lambda:path/2015-03-31/functions/', !GetAtt [ BFunctionSaveArticle, Arn ], '/invocations' ] ]
  UAGResourceArticleId:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !Ref UAGResourceArticle
      PathPart: "{id}"
      RestApiId: !Ref BlogRestApi
  UAGMethodArticleIdGet:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: GET
      ResourceId: !Ref UAGResourceArticleId
      RestApiId: !Ref BlogRestApi
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Join [ "", ['arn:', !Ref 'AWS::Partition', ':apigateway:', !Ref 'AWS::Region', ':lambda:path/2015-03-31/functions/', !GetAtt [ BFunctionGetArticle, Arn ], '/invocations' ] ]
  UAGMethodArticleIdPatch:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: PATCH
      ResourceId: !Ref UAGResourceArticleId
      RestApiId: !Ref BlogRestApi
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Join [ "", ['arn:', !Ref 'AWS::Partition', ':apigateway:', !Ref 'AWS::Region', ':lambda:path/2015-03-31/functions/', !GetAtt [ BFunctionSaveArticle, Arn ], '/invocations' ] ]
  # apparently the below already exists??
  BlogAPIDomainName:
    Type: AWS::ApiGateway::DomainName
    Properties:
      DomainName: blogapi.zenithwebfoundry.com
      EndpointConfiguration:
        Types:
          - EDGE
      CertificateArn: 'arn:aws:acm:us-east-1:499908792600:certificate/2983bc14-28d4-43ab-b1da-fe9618a926d1'
      SecurityPolicy: TLS_1_0
  BlogAPIHostedZone:
    Type: AWS::Route53::HostedZone
    Properties:
      Name: !Ref BlogAPIDomainName
  BlogAPIBasePathMapping:
    Type: AWS::ApiGateway::BasePathMapping
    Properties:
      DomainName: !Ref BlogAPIDomainName
      RestApiId: !Ref BlogRestApi
      Stage: 'prod'
  Route53RecordSetGroup:
    Type: AWS::Route53::RecordSetGroup
    Properties:
      HostedZoneId: Z18TN67OCTIBE0 # zenithwebfoundry.com. HostedZoneId
      RecordSets:
        - Name: blog.zenithwebfoundry.com.
          Type: A
          TTL: '300'
          ResourceRecords:
            - 52.64.238.177
        - Name: blogapi.zenithwebfoundry.com
          Type: A
          AliasTarget:
            HostedZoneId: Z2FDTNDATAQYW2
            DNSName: !Ref BlogAPIDomainName

  AssetsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join [ ".", [ !Ref 'AWS::StackName', 'assets' ] ]
      CorsConfiguration:
        CorsRules:
          - AllowedHeaders: ['*']
            AllowedMethods: [GET,PUT,POST,DELETE,HEAD]
            AllowedOrigins: ['http://localhost*']
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  WebBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join [ ".", [ !Ref 'AWS::StackName', 'web' ] ]
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      WebsiteConfiguration:
        IndexDocument: 'index.html'
        ErrorDocument: 'index.html'


Parameters:
  ArtefactRepositoryBucket:
    Type: String
    Description: 'S3 bucket for the blog artefact zip'
  ArtefactRepositoryKeyPrefix:
    Type: String
    Description: 'S3 key prefix for the blog artefact zip'
  CodeVersion:
    Type: String
    Description: 'Asset version (either just major.minor.patch, or  major.minor.patch-SNAPSHOT)'
  SaveArticleHandler:
    Type: String
    Default: 'com.zenithwebfoundry.blog.api.SaveArticleHandler'
  GetArticleHandler:
    Type: String
    Default: 'com.zenithwebfoundry.blog.api.GetArticleHandler'
  ListArticlesHandler:
    Type: String
    Default: 'com.zenithwebfoundry.blog.api.ListArticlesHandler'
  ParamDnsDomain:
    Description: "Public DNS Zone Name"
    Type: String
    Default: 'zenithwebfoundry.com'

Outputs:
  ArticleEndpoint:
    Value: !Join ["", ['https://', !Ref BlogRestApi, '.execute-api.ap-southeast-2.', !Ref 'AWS::URLSuffix', '/', !Ref BAGDeploymentStageProdArticle, '/'] ]

我遇到困难的部分是 AWS::Route53::RecordSetGroup,特别是 blogapi.zenithwebfoundry.com 的条目。本质上,RecordSetGroup 上的堆栈创建失败,并出现以下错误:

[RRSet with DNS name blogapi.zenithwebfoundry.com., type A contains an alias target that contains a hosted zone 108086391059049046 that is an invalid alias target., Tried to create an alias that targets z2fdtndataqyw2., type A in zone Z08366712O4E48ODE3XHX, but the alias target name does not lie within the target zone]

我尝试了各种排列,包括尝试使用我在此处设置的 HostedZone:

  BlogAPIHostedZone:
    Type: AWS::Route53::HostedZone
    Properties:
      Name: !Ref BlogAPIDomainName

希望这能提供有效的引用,但是,它因不同的错误而失败,本质上是说该记录不存在。

所以我想知道如何使用指向 API Gateway 的别名设置记录集。我见过很多 AWS doco,但它似乎转向区域 API 网关端点(我认为这是一个特殊情况),或者纯粹的控制台风格的指令,它在 RecordSetGroup 之前创建一个 HostedZoneId(允许您对值进行硬编码)。但是如何通过 CloudFormation 模板来做到这一点。

PS:没有 serverless.com 回答 - 这纯粹是关于 AWS CloudFormation 和通过 AWS CLI 部署堆栈。我只对与之相关的答案感兴趣。

编辑 根据建议,我改变了:

DNSName: !Ref BlogAPIDomainName

至:

DNSName: !GetAtt [BlogAPIDomainName, DistributionDomainName]

部署实际完成。所以谢谢你。

最佳答案

谢谢迈克尔。这有帮助。以下是 CloudFormation 配置的相关摘录,可帮助我为 REST API 设置自定义域。

(REST API 通过 CloudFront 分发,具有以下两个类型 A 和 AAAA 的 DNS 路由记录,用于将自定义子域连接到 CloudFront 分发。)

DeliveryApi:
  Type: AWS::ApiGateway::RestApi
  Properties:
    EndpointConfiguration:
      Types:
        - EDGE

DeliveryApiDomainName:
  Type: 'AWS::ApiGateway::DomainName'
  Properties:
    CertificateArn: # Your existing certificate created in the us-east-1 zone, such as arn:aws:acm:us-east-1:829756507488:certificate/23ac8121-f032-4aa7-b013-2d8c7b7c8247
    DomainName: api.example.com
    EndpointConfiguration:
      Types:
        - EDGE

DeliveryApiBasePathMapping:
  Type: 'AWS::ApiGateway::BasePathMapping'
  Properties:
    DomainName: !Ref DeliveryApiDomainName
    RestApiId: !Ref DeliveryApi
    Stage: 'prod'

DeliveryApiRoute53RecordSetGroup:
  Type: AWS::Route53::RecordSetGroup
  Properties:
    HostedZoneId: # Your existing Route 53 hosted zone, such as ZOLE12725GFJ
    RecordSets:
      - Name: api.example.com. # Your chosen subdomain
        Type: A
        AliasTarget:
          HostedZoneId: !GetAtt DeliveryApiDomainName.DistributionHostedZoneId
          DNSName: !GetAtt DeliveryApiDomainName.DistributionDomainName
      - Name: api.example.com.
        Type: AAAA
        AliasTarget:
          HostedZoneId: !GetAtt DeliveryApiDomainName.DistributionHostedZoneId
          DNSName: !GetAtt DeliveryApiDomainName.DistributionDomainName

关于amazon-web-services - 将 Route53 记录集正确的 CloudFormation 发送到 API 网关,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61511520/

相关文章:

amazon-web-services - Cloudformation 无法为 apigateway 创建资源策略

python - 如何从 multipart/form-data 请求中提取二进制数据? (Python)(由 AWS API Gateway 编码的多部分请求 base64)

lambda - 使用 terraform 的自定义 API 网关授权器

amazon-web-services - 自动部署 AWS API Gateway 阶段

python - AWS Boto 实例标记

javascript - Node.js 使用亚马逊转码器格式化视频/音频文件

amazon-web-services - AWS 云形成 : unable to create RDS resource with VPC assigned

amazon-web-services - AWS Kinesis Firehose无法将数据索引到AWS Elasticsearch中

aws-lambda - 如何在 AWS Cloud Formation 模板中为 lambda 指定自定义容器

visual-studio - 避免从 VS 发布到 Cloudformation 时更改主 web.config