如何在 API 网关前添加 CloudFront
How do you add CloudFront in front of API Gateway
API 网关 (APIG),虽然它使用 CloudFront (CF),但不支持 CDN 边缘缓存。当我将 CF 分发配置为使用 APIG 作为自定义来源时,我收到权限被拒绝的错误。
如何配置 CF 来解决这个问题?
在 API 网关 (APIG) 通过其内部使用 CloudFront (CF) 支持边缘缓存之前,我想出了一个解决方法。
您确实可以将 CF dist 放在 APIG 前面,诀窍是强制仅使用 HTTPS "Viewer Protocol Policy" 并且 NOT 转发 HOST header 因为 APIG 需要 SNI。
我将我的 CF "Default Cache Behavior Settings" 设置为不转发任何 header,并强制 "Viewer Protocol Policy" 到 "HTTPS Only",它起作用了。希望这对其他人有帮助。
这是具有所有必需配置的 CloudFormation 资源 object(注意:我对 StackName 使用约定 <stage>--<app name>
):
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
IPV6Enabled: true
HttpVersion: http2
Comment: !Join [ '--', [!Ref 'AWS::StackName', ' Cloud Front']]
Aliases: [!Ref CloudFrontCname]
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArn
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1.1_2016
Origins:
- Id: APIGOrigin
DomainName: !Sub
- ${apigId}.execute-api.${AWS::Region}.amazonaws.com
- { apigId: !Ref ApiGatewayLambdaProxy }
OriginPath: !Sub
- /${Stage}
- { Stage: !Select [ "0", !Split [ '--', !Ref 'AWS::StackName' ] ] }
CustomOriginConfig:
# HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginCustomHeaders:
- HeaderName: 'Verify-From-Cf'
HeaderValue: !Ref VerifyFromCfHeaderVal
DefaultCacheBehavior:
AllowedMethods: ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
CachedMethods: ["GET", "HEAD", "OPTIONS"]
ForwardedValues:
Headers:
- Access-Control-Request-Headers
- Access-Control-Request-Method
- Origin
- Authorization
# - Host APIG needs to use SNI
QueryString: true
TargetOriginId: APIGOrigin
ViewerProtocolPolicy: https-only
Compress: true
DefaultTTL: 0
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 400
- ErrorCachingMinTTL: 1
ErrorCode: 403
- ErrorCachingMinTTL: 5
ErrorCode: 500
DNSARecord:
Type: AWS::Route53::RecordSet
Properties:
Comment: !Ref 'AWS::StackName'
Name: !Ref CloudFrontCname
Type: A
HostedZoneName: !Join ['.', [ !Select [1, !Split ['.', !Ref CloudFrontCname]], !Select [2, !Split ['.', !Ref CloudFrontCname]], '']]
AliasTarget:
HostedZoneId: !Ref Route53HostedZoneId
DNSName: !GetAtt CloudFront.DomainName
DNSAAAARecord:
Type: AWS::Route53::RecordSet
Properties:
Comment: !Ref 'AWS::StackName'
Name: !Ref CloudFrontCname
Type: AAAA
HostedZoneName: !Join ['.', [ !Select [1, !Split ['.', !Ref CloudFrontCname]], !Select [2, !Split ['.', !Ref CloudFrontCname]], '']]
AliasTarget:
HostedZoneId: !Ref Route53HostedZoneId
DNSName: !GetAtt CloudFront.DomainName
2018 年底更新
- CloudFormation 终于支持设置 SSL 协议版本:
MinimumProtocolVersion: TLSv1.1_2016
- 我已经将这个(以及许多其他)最佳实践融入到一个 OSS 项目中:aws-blueprint
如果 API 网关 returns 403 错误:
Authorization header requires 'Credential' parameter. Authorization
header requires 'Signature' parameter. Authorization header requires
'SignedHeaders' parameter. Authorization header requires existence of
either a 'X-Amz-Date' or a 'Date' header.
也可能是源端点不正确。 "API Gateway treats all errors to non-existent paths as 403 permission denied errors rather than a 404 not found error."(参见 this support thread)。
我收到此错误并假设我错误地转发了授权 header,但我只是错误地配置了原始路径。
添加到以前的答案:
重要的是行为路径模式实际上是匹配 "real" 路径的东西。
如果API端点是<id>.execute-api.<region>.amazonaws.com/stage-name/my-api
源域+路径为<id>.execute-api.<region>.amazonaws.com/stage-name
行为路径模式 必须是 my-api
、my-api/*
、my-api/something
等
我不知道为什么,但我认为路径模式可以用作别名,例如:
https://www.example.com/random-name(路径模式random-name
)解析为域+原始路径集,例如<id>.execute-api.<region>.amazonaws.com/stage-name
.
事实并非如此。
随着 2017 年 11 月 API 网关区域端点的推出,我相信现在最好将它们与 CloudFront Distributions 一起使用。有关从边缘优化 API 迁移到区域 API 以及设置 CloudFront 分配的一些详细说明,请参见此处:
我只想在这里重申,对于遵循 AWS 高级支持知识中心指南的任何人,
How do I set up API Gateway with my own CloudFront distribution?
https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-cloudfront-distribution/
如果您使用 AWS 控制台设置 CloudFront 分配,根本原因是您将 Cache Based on Selected Request Headers 设置为 全部.
将其设置为None或排除白名单中的Host
header即可解决问题。
API 网关 (APIG),虽然它使用 CloudFront (CF),但不支持 CDN 边缘缓存。当我将 CF 分发配置为使用 APIG 作为自定义来源时,我收到权限被拒绝的错误。
如何配置 CF 来解决这个问题?
在 API 网关 (APIG) 通过其内部使用 CloudFront (CF) 支持边缘缓存之前,我想出了一个解决方法。
您确实可以将 CF dist 放在 APIG 前面,诀窍是强制仅使用 HTTPS "Viewer Protocol Policy" 并且 NOT 转发 HOST header 因为 APIG 需要 SNI。
我将我的 CF "Default Cache Behavior Settings" 设置为不转发任何 header,并强制 "Viewer Protocol Policy" 到 "HTTPS Only",它起作用了。希望这对其他人有帮助。
这是具有所有必需配置的 CloudFormation 资源 object(注意:我对 StackName 使用约定 <stage>--<app name>
):
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
IPV6Enabled: true
HttpVersion: http2
Comment: !Join [ '--', [!Ref 'AWS::StackName', ' Cloud Front']]
Aliases: [!Ref CloudFrontCname]
ViewerCertificate:
AcmCertificateArn: !Ref AcmCertificateArn
SslSupportMethod: sni-only
MinimumProtocolVersion: TLSv1.1_2016
Origins:
- Id: APIGOrigin
DomainName: !Sub
- ${apigId}.execute-api.${AWS::Region}.amazonaws.com
- { apigId: !Ref ApiGatewayLambdaProxy }
OriginPath: !Sub
- /${Stage}
- { Stage: !Select [ "0", !Split [ '--', !Ref 'AWS::StackName' ] ] }
CustomOriginConfig:
# HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: https-only
OriginCustomHeaders:
- HeaderName: 'Verify-From-Cf'
HeaderValue: !Ref VerifyFromCfHeaderVal
DefaultCacheBehavior:
AllowedMethods: ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
CachedMethods: ["GET", "HEAD", "OPTIONS"]
ForwardedValues:
Headers:
- Access-Control-Request-Headers
- Access-Control-Request-Method
- Origin
- Authorization
# - Host APIG needs to use SNI
QueryString: true
TargetOriginId: APIGOrigin
ViewerProtocolPolicy: https-only
Compress: true
DefaultTTL: 0
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 400
- ErrorCachingMinTTL: 1
ErrorCode: 403
- ErrorCachingMinTTL: 5
ErrorCode: 500
DNSARecord:
Type: AWS::Route53::RecordSet
Properties:
Comment: !Ref 'AWS::StackName'
Name: !Ref CloudFrontCname
Type: A
HostedZoneName: !Join ['.', [ !Select [1, !Split ['.', !Ref CloudFrontCname]], !Select [2, !Split ['.', !Ref CloudFrontCname]], '']]
AliasTarget:
HostedZoneId: !Ref Route53HostedZoneId
DNSName: !GetAtt CloudFront.DomainName
DNSAAAARecord:
Type: AWS::Route53::RecordSet
Properties:
Comment: !Ref 'AWS::StackName'
Name: !Ref CloudFrontCname
Type: AAAA
HostedZoneName: !Join ['.', [ !Select [1, !Split ['.', !Ref CloudFrontCname]], !Select [2, !Split ['.', !Ref CloudFrontCname]], '']]
AliasTarget:
HostedZoneId: !Ref Route53HostedZoneId
DNSName: !GetAtt CloudFront.DomainName
2018 年底更新
- CloudFormation 终于支持设置 SSL 协议版本:
MinimumProtocolVersion: TLSv1.1_2016
- 我已经将这个(以及许多其他)最佳实践融入到一个 OSS 项目中:aws-blueprint
如果 API 网关 returns 403 错误:
Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header.
也可能是源端点不正确。 "API Gateway treats all errors to non-existent paths as 403 permission denied errors rather than a 404 not found error."(参见 this support thread)。
我收到此错误并假设我错误地转发了授权 header,但我只是错误地配置了原始路径。
添加到以前的答案:
重要的是行为路径模式实际上是匹配 "real" 路径的东西。
如果API端点是<id>.execute-api.<region>.amazonaws.com/stage-name/my-api
源域+路径为<id>.execute-api.<region>.amazonaws.com/stage-name
行为路径模式 必须是 my-api
、my-api/*
、my-api/something
等
我不知道为什么,但我认为路径模式可以用作别名,例如:
https://www.example.com/random-name(路径模式random-name
)解析为域+原始路径集,例如<id>.execute-api.<region>.amazonaws.com/stage-name
.
事实并非如此。
随着 2017 年 11 月 API 网关区域端点的推出,我相信现在最好将它们与 CloudFront Distributions 一起使用。有关从边缘优化 API 迁移到区域 API 以及设置 CloudFront 分配的一些详细说明,请参见此处:
我只想在这里重申,对于遵循 AWS 高级支持知识中心指南的任何人,
How do I set up API Gateway with my own CloudFront distribution? https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-cloudfront-distribution/
如果您使用 AWS 控制台设置 CloudFront 分配,根本原因是您将 Cache Based on Selected Request Headers 设置为 全部.
将其设置为None或排除白名单中的Host
header即可解决问题。