SAM 使用单个自定义域名将 s3 网站添加到 API 网关 + Lambda
SAM Adding s3 website to API Gateway + Lambda with single custom domain name
我正在努力在单个自定义域(例如:mysub.domain.com)上创建笔记应用程序(api + 网站)。我想要
- API 我所有 Lambda 的网关都可以通过 /api/
的路径访问
- 让域的其余路径从 s3 静态网站提供服务
目前,
- 我的 lambda 端点在 https://mysub.domain.com/api/notes 上工作(SSL 已经在 AWS 控制台中工作)
- 通过 BasePathMapping(参见下面的 yaml)
- 已经为我的子域添加了 CNAME 记录,指向使用
$ sam deploy
创建的 Cloudfront 端点
Parameters:
DomainName:
Type: String
Default: mysub.nydomain.com
Resources:
####### DOMAIN - START ######
AppDomainName:
Type: AWS::ApiGateway::DomainName
Properties:
CertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/1b23c456-7890-1b2b-a345-a6bb4a7fa89c
DomainName: !Ref DomainName
APIBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
BasePath: 'api'
DomainName: !Ref AppDomainName
RestApiId: !Ref ServerlessRestApi
Stage: !Ref ServerlessRestApiProdStage
####### LAMBDA - START ######
NotesFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: notes/
Handler: app.lambdaHandler
Runtime: nodejs12.x
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref NotesTable
Events:
Notes:
Type: Api
Properties:
Path: /notes
Method: post
####### TABLES - START ######
NotesTable:
Type: AWS::DynamoDB::Table
Properties:
...
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
NotesApi:
Description: "API Gateway endpoint URL for Prod stage for Notes function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/bt-device-history/"
NotesFunction:
Description: "Hello World Lambda Function ARN"
Value: "DeviceHistoryFunction"
NotesFunctionIamRole:
Description: "Implicit IAM Role created for NotesFunction"
Value: !GetAtt NotesFunctionRole.Arn
当我将以下内容(s3 存储桶和 Cloudfront 分发)添加到我的 SAM YAML 模板的资源部分时
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref 'DomainName'
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: 404.html
DeletionPolicy: Retain
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'WebsiteBucket'
PolicyDocument:
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: s3:GetObject
Resource: !Join ['', ['arn:aws:s3:::', !Ref 'WebsiteBucket', /*]]
WebsiteCloudfront:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebsiteBucket
Properties:
DistributionConfig:
Comment: Cloudfront Distribution pointing to S3 bucket
Origins:
- DomainName: !Select [2, !Split ["/", !GetAtt WebsiteBucket.WebsiteURL]]
Id: S3Origin
CustomOriginConfig:
HTTPPort: '80'
HTTPSPort: '443'
OriginProtocolPolicy: http-only
Enabled: true
HttpVersion: 'http2'
DefaultRootObject: index.html
Aliases:
- !Ref 'DomainName'
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
Compress: true
TargetOriginId: S3Origin
ForwardedValues:
QueryString: true
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_All
ViewerCertificate:
AcmCertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/1bf2c345--6789-0b1b-a123-a4bb5a6fa44c
SslSupportMethod: sni-only
WebsiteDNSName:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: !Join ['', [!Ref 'DomainName', .]]
RecordSets:
- Name: !Ref 'DomainName'
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt [WebsiteCloudfront, DomainName]
我在 $sam deploy
中收到以下错误
AWS::CloudFront::Distribution WebsiteCloudfront One or more of the CNAMEs you provided are already associated with a
different resource. (Service: AmazonCloudFront; Status Code: 409; Error
Code: CNAMEAlreadyExists; Request ID:
e044dd29-4550-4f86-be44-22bbf7c34b16)
AWS::CloudFormation::Stack note-app The following resource(s) failed to create: [WebsiteCloudfront].
我的静态网站如何使用单个自定义域并且 api 需要使用 SAM 模板模型?
你会:
- 设置具有两个来源的 CloudFront,S3 和 API 网关。
- 使用 API 网关代理您的 s3 端点
我正在努力在单个自定义域(例如:mysub.domain.com)上创建笔记应用程序(api + 网站)。我想要
- API 我所有 Lambda 的网关都可以通过 /api/ 的路径访问
- 让域的其余路径从 s3 静态网站提供服务
目前,
- 我的 lambda 端点在 https://mysub.domain.com/api/notes 上工作(SSL 已经在 AWS 控制台中工作)
- 通过 BasePathMapping(参见下面的 yaml)
- 已经为我的子域添加了 CNAME 记录,指向使用
$ sam deploy
创建的 Cloudfront 端点
Parameters:
DomainName:
Type: String
Default: mysub.nydomain.com
Resources:
####### DOMAIN - START ######
AppDomainName:
Type: AWS::ApiGateway::DomainName
Properties:
CertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/1b23c456-7890-1b2b-a345-a6bb4a7fa89c
DomainName: !Ref DomainName
APIBasePathMapping:
Type: AWS::ApiGateway::BasePathMapping
Properties:
BasePath: 'api'
DomainName: !Ref AppDomainName
RestApiId: !Ref ServerlessRestApi
Stage: !Ref ServerlessRestApiProdStage
####### LAMBDA - START ######
NotesFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: notes/
Handler: app.lambdaHandler
Runtime: nodejs12.x
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref NotesTable
Events:
Notes:
Type: Api
Properties:
Path: /notes
Method: post
####### TABLES - START ######
NotesTable:
Type: AWS::DynamoDB::Table
Properties:
...
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
NotesApi:
Description: "API Gateway endpoint URL for Prod stage for Notes function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/bt-device-history/"
NotesFunction:
Description: "Hello World Lambda Function ARN"
Value: "DeviceHistoryFunction"
NotesFunctionIamRole:
Description: "Implicit IAM Role created for NotesFunction"
Value: !GetAtt NotesFunctionRole.Arn
当我将以下内容(s3 存储桶和 Cloudfront 分发)添加到我的 SAM YAML 模板的资源部分时
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref 'DomainName'
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: 404.html
DeletionPolicy: Retain
WebsiteBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref 'WebsiteBucket'
PolicyDocument:
Statement:
- Sid: PublicReadForGetBucketObjects
Effect: Allow
Principal: '*'
Action: s3:GetObject
Resource: !Join ['', ['arn:aws:s3:::', !Ref 'WebsiteBucket', /*]]
WebsiteCloudfront:
Type: AWS::CloudFront::Distribution
DependsOn:
- WebsiteBucket
Properties:
DistributionConfig:
Comment: Cloudfront Distribution pointing to S3 bucket
Origins:
- DomainName: !Select [2, !Split ["/", !GetAtt WebsiteBucket.WebsiteURL]]
Id: S3Origin
CustomOriginConfig:
HTTPPort: '80'
HTTPSPort: '443'
OriginProtocolPolicy: http-only
Enabled: true
HttpVersion: 'http2'
DefaultRootObject: index.html
Aliases:
- !Ref 'DomainName'
DefaultCacheBehavior:
AllowedMethods:
- GET
- HEAD
Compress: true
TargetOriginId: S3Origin
ForwardedValues:
QueryString: true
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_All
ViewerCertificate:
AcmCertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/1bf2c345--6789-0b1b-a123-a4bb5a6fa44c
SslSupportMethod: sni-only
WebsiteDNSName:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: !Join ['', [!Ref 'DomainName', .]]
RecordSets:
- Name: !Ref 'DomainName'
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt [WebsiteCloudfront, DomainName]
我在 $sam deploy
AWS::CloudFront::Distribution WebsiteCloudfront One or more of the CNAMEs you provided are already associated with a
different resource. (Service: AmazonCloudFront; Status Code: 409; Error
Code: CNAMEAlreadyExists; Request ID:
e044dd29-4550-4f86-be44-22bbf7c34b16)
AWS::CloudFormation::Stack note-app The following resource(s) failed to create: [WebsiteCloudfront].
我的静态网站如何使用单个自定义域并且 api 需要使用 SAM 模板模型?
你会:
- 设置具有两个来源的 CloudFront,S3 和 API 网关。
- 使用 API 网关代理您的 s3 端点