Getting an error trying to create an AWS API Gateway via Cloudformation

时间:2018-06-05 05:05:56

标签: aws-api-gateway amazon-cloudformation

I'm trying to make a simple Cloudformation to create a website hosted on S3 with an API Gateway backend. Everything seems OK as far as I can tell but I get errors when trying to create the API Gateway:

Errors found during import: Unable to put integration on 'ANY' for resource at path '/{proxy+}': AWS ARN for integration must contain path or action (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: b28983d9-687c-11e8-8692-27df1db97456)

The gateway should just be a single route that sends everything to a single lambda. Should be super simple.

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Website S3 Hosted, API Gateway Backend
Parameters:
  DomainName:
    Type: String
    Description: The DNS name of an Amazon Route 53 hosted zone e.g. server.com
    AllowedPattern: '(?!-)[a-zA-Z0-9-.]{1,63}(?<!-)'
    ConstraintDescription: must be a valid DNS zone name.
Mappings:
  S3RegionMap:
    us-east-1:
      S3HostedZoneId: Z3AQBSTGFYJSTF
      S3WebsiteEndpoint: s3-website-us-east-1.amazonaws.com
    us-west-1:
      S3HostedZoneId: Z2F56UZL2M1ACD
      S3WebsiteEndpoint: s3-website-us-west-1.amazonaws.com
    us-west-2:
      S3HostedZoneId: Z3BJ6K6RIION7M
      S3WebsiteEndpoint: s3-website-us-west-2.amazonaws.com
    eu-west-1:
      S3HostedZoneId: Z1BKCTXD74EZPE
      S3WebsiteEndpoint: s3-website-eu-west-1.amazonaws.com
    ap-southeast-1:
      S3HostedZoneId: Z3O0J2DXBE1FTB
      S3WebsiteEndpoint: s3-website-ap-southeast-1.amazonaws.com
    ap-southeast-2:
      S3HostedZoneId: Z1WCIGYICN2BYD
      S3WebsiteEndpoint: s3-website-ap-southeast-2.amazonaws.com
    ap-northeast-1:
      S3HostedZoneId: Z2M4EHUR26P7ZW
      S3WebsiteEndpoint: s3-website-ap-northeast-1.amazonaws.com
    sa-east-1:
      S3HostedZoneId: Z31GFT0UA1I2HV
      S3WebsiteEndpoint: s3-website-sa-east-1.amazonaws.com
Resources:
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: '/'
      Policies:
      - PolicyName: execution
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource: '*'
          - Effect: Allow
            Action:
            - s3:GetObject
            - s3:PutObject
            - s3:ListBucket
            Resource: '*'
          - Effect: Allow
            Action:
            - ec2:DescribeNetworkInterfaces
            - ec2:CreateNetworkInterface
            - ec2:DeleteNetworkInterface
            Resource: '*'
          - Effect: Allow
            Action:
            - cognito-idp:AdminGetUser
            - cognito-idp:AdminUpdateUserAttributes
            Resource: '*'
  APIGatewayExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: apigateway.amazonaws.com
          Action:
          - sts:AssumeRole
      Path: '/'
      Policies:
      - PolicyName: execution
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource: '*'
          - Effect: Allow
            Action:
            - lambda:InvokeFunction
            Resource: '*'
  LambdaFunctionAPI:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: exports.handler = function (event, context, callback) { callback(null, event); };
      Handler: index.handler
      MemorySize: 128
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: nodejs4.3
      Timeout: 30
  APIGateway:
    Type: AWS::ApiGateway::RestApi
    Properties:              
      FailOnWarnings: true
      Name: !Join ['-', !Split ['.', !Join ['.', ['api', !Ref DomainName]]]]
      Body:
        swagger: '2.0'
        info:
          version: 0.0.1
          title: !Join [' ', ['API route for', !Ref DomainName]]
        basePath: '/api'
        paths:
          '/{proxy+}':
            options:
              summary: CORS support
              description: |
                Enable CORS by returning correct headers
              consumes:
                - application/json
              produces:
                - application/json
              tags:
                - CORS
              x-amazon-apigateway-integration:
                type: mock
                requestTemplates:
                  application/json: |
                    {
                      "statusCode" : 200
                    }
                responses:
                  "default":
                    statusCode: "200"
                    responseParameters:
                      method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
                      method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
                      method.response.header.Access-Control-Allow-Origin: "'*'"
                    responseTemplates:
                      application/json: |
                        {}
              responses:
                '200':
                  description: Default response for CORS method
                  headers:
                    Access-Control-Allow-Headers:
                      type: "string"
                    Access-Control-Allow-Methods:
                      type: "string"
                    Access-Control-Allow-Origin:
                      type: "string"
            x-amazon-apigateway-any-method:
              produces:
              - "application/json"
              responses:
                '200':
                  description: "200 response"
                  schema:
                    $ref: "#/definitions/Empty"
              x-swagger-router-controller: main
              x-amazon-apigateway-integration:
                type: aws_proxy
                httpMethod: POST
                uri: !GetAtt LambdaFunctionAPI.Arn
                credentials: !Ref APIGatewayExecutionRole

        definitions:
          Empty:
            type: "object"
            title: "Empty Schema"
  APIDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref APIGateway
      Description: Deploy for live
      StageName: Live
  WebsiteBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        Ref: DomainName
      AccessControl: PublicRead
      WebsiteConfiguration:
        IndexDocument: index.html
        ErrorDocument: 404.html
      Tags:
      - Key: Name
        Value: !Join ['_', ['WebsiteBucket', !Ref 'AWS::StackName']]
      - Key: Domain
        Value: !Ref DomainName
    DeletionPolicy: Retain
  WWWBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join ['.', ['www', !Ref DomainName]]
      AccessControl: PublicRead
      WebsiteConfiguration:
        RedirectAllRequestsTo:
          HostName: !Ref WebsiteBucket
      Tags:
      - Key: Name
        Value: !Join ['_', ['WWWBucket', !Ref 'AWS::StackName']]
      - Key: Domain
        Value: !Ref DomainName
  WebsiteBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref WebsiteBucket
      PolicyDocument:
        Statement:
        - Action:
          - s3:GetObject
          Effect: Allow
          Resource: !Join ['', ['arn:aws:s3:::', !Ref WebsiteBucket, '/*']]
          Principal: '*'
  WWWBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref WWWBucket
      PolicyDocument:
        Statement:
        - Action:
          - s3:GetObject
          Effect: Allow
          Resource: !Join ['', ['arn:aws:s3:::', !Ref WWWBucket, '/*']]
          Principal: '*'
  DNS:
    Type: AWS::Route53::HostedZone
    Properties:
      HostedZoneConfig:
        Comment: !Join [' ', ['Hosted zone for', !Ref DomainName]]
      Name: !Ref DomainName
      HostedZoneTags:
      - Key: Application
        Value: Blog
  DNSRecord:
    Type: AWS::Route53::RecordSetGroup
    DependsOn: DNS
    Properties:
      HostedZoneName:
        Fn::Join: ['', [!Ref DomainName, '.']]
      Comment: Zone records.
      RecordSets:
      - Name: !Ref DomainName
        Type: A
        AliasTarget:
          HostedZoneId: !FindInMap [S3RegionMap, !Ref 'AWS::Region', S3HostedZoneId]
          DNSName: !FindInMap [S3RegionMap, !Ref 'AWS::Region', S3WebsiteEndpoint]
      - Name: !Join ['.', ['www', !Ref DomainName]]
        Type: A
        AliasTarget:
          HostedZoneId: !FindInMap [S3RegionMap, !Ref 'AWS::Region', S3HostedZoneId]
          DNSName: !FindInMap [S3RegionMap, !Ref 'AWS::Region', S3WebsiteEndpoint]
Outputs:
  S3WebsiteURL:
    Value: !GetAtt WebsiteBucket.WebsiteURL
    Description: URL for website hosted on S3

1 个答案:

答案 0 :(得分:1)

用于连接Lambda的URI不是Lambda的Arn,而是API网关调用URI。此外,您需要将凭据行从ref更改为执行角色的Arn

以下是更改部分的简短摘录:

x-amazon-apigateway-integration:
  type: aws_proxy
  httpMethod: POST
  uri: !Sub  "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunctionAPI.Arn}/invocations"
  credentials: !GetAtt APIGatewayExecutionRole.Arn