Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit AWS API Gateway access to specific CloudFront distribution or Route53 subdomain

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.

like image 882
Jon B Avatar asked Sep 27 '19 01:09

Jon B


2 Answers

"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.

like image 195
NoPathInParticular Avatar answered Nov 10 '22 00:11

NoPathInParticular


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"
like image 26
jellycsc Avatar answered Nov 09 '22 23:11

jellycsc