尝试通过 Cloudformation 创建 AWS API 网关时出错
Posted
技术标签:
【中文标题】尝试通过 Cloudformation 创建 AWS API 网关时出错【英文标题】:Getting an error trying to create an AWS API Gateway via Cloudformation 【发布时间】:2018-11-14 11:42:09 【问题描述】:我正在尝试制作一个简单的 Cloudformation 来创建一个托管在 S3 上并带有 API 网关后端的网站。据我所知,一切似乎都很好,但是在尝试创建 API 网关时出现错误:
导入期间发现错误:无法将路径“/proxy+”的资源的集成放在“ANY”上:用于集成的 AWS ARN 必须包含路径或操作(服务:AmazonApiGateway;状态代码:400;错误代码:BadRequestException ; 请求 ID:b28983d9-687c-11e8-8692-27df1db97456)
网关应该只是将所有内容发送到单个 lambda 的单个路由。应该超级简单。
---
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】:您应该用来连接到 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
【讨论】:
从哪里获得 Lambda 的 API 网关调用 URI? 您可以使用 jens walter 提供的模板构建它:“arn:aws:apigateway:$AWS::Region:lambda:path/2015-03-31/functions/$LambdaFunctionAPI. Arn/调用”以上是关于尝试通过 Cloudformation 创建 AWS API 网关时出错的主要内容,如果未能解决你的问题,请参考以下文章
通过 cloudformation 为 fargate 启动类型任务创建 cloudwatch 事件规则的“目标”
CloudFormation - 为 DynamoDB 创建表启用 TTL
如何在 cloudformation“Fn::Sub”中转义“$”