I have an API Gateway api setup that I want to limit access to. I have a subdomain setup in AWS Route 53 that points to a CloudFront distribution where my app lives. This app makes a POST request to the API.
I have looked into adding a resource policy for my api based on the example 'AWS API Whitelist' but I can't seem to get the syntax correct, I constantly get errors.
I also tried creating an IAM user and locking down the API with AWS_IAM auth but then I need to create a signed request which seems like a lot of work that should be a lot easier via resource policies?
This is an example of the resource policy I tried to attach to my API:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity {{CloudFrontID}}"
},
"Action": "execute-api:Invoke",
"Resource": [
"execute-api:/*/*/*"
]
}
]
}
This returns the following error:
Invalid policy document. Please check the policy syntax and ensure that Principals are valid.
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity {{CloudFrontID}}"
The problem with this concept is that this is a public HTTP request. Unless it's a signed request, AWS will not know about any IAM or ARN resources, it just knows it has a standard HTTP request. If you make the request with a curl -v command you will see the request parameters look something like this:
GET /test/mappedcokerheaders HTTP/2 Host: APIID.execute-api.REGION.amazonaws.com User-Agent: curl/7.61.1 Accept: */*
It's possible you could filter the user Agent as I do see that condition defined here.
I would check all of the values that are coming in the request from cloudfront vs the request from your curl directly to the API by trapping the api gw request id in the response headers, and looking for those in your API Gateway Access Logs. You'll have to enable Access Logs though, and define what parameters you want logged, which you can see how to do here.
The problem is that OAI cannot be used in CustomOrigin. If you are not forwarding User-Agent
to the API Gateway CustomOrigin, then the simplest approach for you is to add a resource policy in API Gateway which only allows aws:UserAgent: "Amazon CloudFront"
.
Be careful: User-Agent
can very easily be spoofed. This approach is designed to only prevent "normal access" like a random bot on the web is trying to scrape your site.
The User-Agent
header is guaranteed to be Amazon CloudFront
. See the quote from Request and Response Behavior for Custom Origins.
Behavior If You Don't Configure CloudFront to Cache Based on Header Values: CloudFront replaces the value of this header field with
Amazon CloudFront
. If you want CloudFront to cache your content based on the device the user is using, see Configuring Caching Based on the Device Type.
Here is how the full resource policy looks like:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-west-2:123456789012:abcdefghij/*/*/*",
"Condition": {
"StringEquals": {
"aws:UserAgent": "Amazon CloudFront"
}
}
}
]
}
Here is how to configure it in serverless.yml
:
provider:
resourcePolicy:
- Effect: Allow
Principal: "*"
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
Condition:
StringEquals:
aws:UserAgent: "Amazon CloudFront"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With