Is it possible to use IAM Roles Authentication to an API Gateway endpoint via Cloudfront?
Here is a basic use case:
- /api -> API Gateway
- /* -> S3 HTML/Javascript
I've been able to get this working without Authentication similar to the following setup: https://www.codeengine.com/articles/process-form-aws-api-gateway-lambda/
How do you add CloudFront in front of API Gateway
Of particular note is to NOT forward the HOST header from Cloudfront...
When I enable IAM Authentication in the API, I receive the following response:
OPTIONS: 200
POST: 403
{"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'POST\n/test/create\n\naccept:application/json\ncontent-type:application/json\nhost:*****.execute-api.ap-****-2.amazonaws.com\nx-amz-date:20170328T044253Z\n\naccept;content-type;host;x-amz-date\na57656a9def890d9de2b637789f7e5917f4b2823765ae0122087d08f89a97380'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\n20170328T044253Z\n20170328/ap-southeast-2/execute-api/aws4_request\ncae7fd6b4cabd593ad2ec6ce7091c94dc8cba306e81da95d567873eea8f981a5'\n"}
The host in the Canonical String is that of the API Gateway...
-
1You'll need to sign the request as if you were going to send it directly to API Gateway... then change the hostname in the request after signing. It's counter-intuitive, perhaps, but since CloudFront is going to change it back, again, this seems like the only solution.Michael - sqlbot– Michael - sqlbot2017年03月28日 13:00:04 +00:00Commented Mar 28, 2017 at 13:00
-
Possible duplicate of Does API Gateway behind CloudFront not support AWS_IAM authentication?Reed Hermes– Reed Hermes2019年01月22日 16:23:46 +00:00Commented Jan 22, 2019 at 16:23
-
@HungryTuna That question was asked Feb 15 '18... Can you please elaborate?atlas_scoffed– atlas_scoffed2019年01月22日 23:08:58 +00:00Commented Jan 22, 2019 at 23:08
3 Answers 3
As noted in comments, you'll run into difficulties due to the change of the HOST header. In theory signing the request with the API Gateway exceute-api domain as the value of HOST in theory should work, assuming CloudFront is not changing the payload in any other way.
5 Comments
If you want to support API Gateway that has AWS_IAM authentication when it is behind CloudFront, your best option is to create a custom domain and use it in your CloudFront distribution and then set the same custom domain in your API Gateway and make sure to map it to your API Gateway resource.
Also Make sure to configure the Origin request policy to use a predefined policy called "AllViwer" which is basically a Policy to forward all parameters in viewer requests.
This a YML file that basically creates a CloudFront Distribution with a custom domain and assigns "AllViwer" in Origin request policy, and uses a custom caching policy that only consider the URL along with the query strings as part of the caching key.
Conditions:
IsProd:
Fn::Equals:
- ${self:provider.stage}
- prod
Resources:
CloudFrontCachePolicy:
Type: AWS::CloudFront::CachePolicy
Properties:
CachePolicyConfig:
Name: "QueryStringOnlyCachePolicy"
Comment: "Cache policy that considers only the query string"
MinTTL: 86400 # 1 day
MaxTTL: 31536000 # 1 year
DefaultTTL: 7884000 # 3 months
ParametersInCacheKeyAndForwardedToOrigin:
CookiesConfig:
CookieBehavior: "none"
HeadersConfig:
HeaderBehavior: "none"
QueryStringsConfig:
QueryStringBehavior: "all"
EnableAcceptEncodingGzip: false
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
HttpVersion: "http2"
Aliases:
Fn::If:
- IsProd
- ["anything.yourdomain.app"]
- ["anything.dev.yourdomain.app"]
Comment: My Service Service CloudFront Distribution
DefaultCacheBehavior:
TargetOriginId: MyApiGatewayServiceOrigin
ViewerProtocolPolicy: "redirect-to-https"
AllowedMethods: ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
OriginRequestPolicyId: "216adef6-5c7f-47e4-b989-5492eafa07d3" # Predefined Managed Policy called "AllViewer"
CachePolicyId:
Ref: CloudFrontCachePolicy
Origins:
- Id: MyApiGatewayServiceOrigin
DomainName:
Fn::Join:
- ""
- - Ref: HttpApi
- ".execute-api."
- Ref: AWS::Region
- ".amazonaws.com"
CustomOriginConfig:
OriginProtocolPolicy: "https-only"
OriginSSLProtocols:
- "TLSv1.2"
ViewerCertificate:
AcmCertificateArn:
Fn::If:
- IsProd
- "arn:aws:acm:region:account-id:certificate/prod-certificate-id"
- "arn:aws:acm:region:account-id:certificate/dev-certificate-id"
MinimumProtocolVersion: "TLSv1.2_2021"
SslSupportMethod: "sni-only"
Comments
This is a difficult one to debug, I wrote a blog here going into more detail on the solution, hope it helps someone else. Thanks @Bob for putting me on the right track: https://www.rehanvdm.com/serverless/cloudfront-reverse-proxy-api-gateway-to-prevent-cors/index.html
Comments
Explore related questions
See similar questions with these tags.