Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS API Gateway returns a 403 with x-amzn-ErrorType:AccessDeniedException header

The context

I have a serverless web app built with AWS trio: API Gateway + Lambda + DynamoDB. The first page of the app send 2 http requests to get data and combine reponses to print the result.

            / APIGateway /projects      => Lambda (DynamoDB request)   \
web app => {                                                            } => display data
            \ APIGateway /organizations => Lambda (Github API request) /

The problem

Every goes fine the first time I ask for the page. But if I try to refresh this page, I get a 403 error on /organizations request. From there, if I wait ~3-5 minutes and I refresh the page again I correctly see all the data and my page is perfectly displayed. Sometimes, the GET /organizations fails, sometimes, it's the GET /projects.

Why I have to wait to be able to correctly refresh the page ? How can I fix it ?

Additional informations

When I have this 403 error, ...

  • I get a 200 OK response to the OPTIONS /organizations request
  • I don't see the GET /organizations request at all in the cloudwatch log (the OPTIONS request is there, but not the GET)
  • Response headers are:

    Connection:keep-alive
    Content-Length:60
    Content-Type:application/json
    Date:Mon, 12 Dec 2016 11:31:29 GMT
    Via:1.1 af2dd53407c5eae7ddf5c44e27a5dd1b.cloudfront.net (CloudFront)
    X-Amz-Cf-Id:Kl1JS1ZCCJuGAmydXv3qDoq3E-rFZrlZbs8Bgvw8RSrb8xsjEyAJNQ==
    x-amzn-ErrorType:AccessDeniedException
    x-amzn-RequestId:8689b86c-c05e-11e6-b851-7ff70d9a3125
    X-Cache:Error from cloudfront
    

    (I dont know why I have x-amzn-ErrorType:AccessDeniedException and X-Cache:Error from cloudfront)

  • I have a CORS error in my chrome console :

    XMLHttpRequest cannot load https://********.execute-api.eu-central-1.amazonaws.com/prod/organizations. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403.
    

    (... even if CORS is enabled and Access-Control-Allow-Origin:* is present in the OPTIONS response headers)

Thanks for your help!

like image 451
Sylvain Avatar asked Dec 12 '16 12:12

Sylvain


People also ask

Why do I get an HTTP 403 Forbidden error when connecting to my API gateway APIs from a VPC?

The HTTP 403 Forbidden error most commonly occurs when private DNS is enabled for an API Gateway interface VPC endpoint that's associated with a VPC. In this scenario, all requests from the VPC to API Gateway APIs resolve to that interface VPC endpoint.

What are most likely causes If an API starts to send 403 status codes randomly for requests?

The most common cause of a 403 Forbidden Error is simply inputting an incorrect URL. As discussed before, many tightly secured web servers disallow access to improper URLs. This could be anything from accessing a file directory to accessing a private page meant for other users.

How do I fix a 403 postman error?

The simple answer is; “You need to be given the correct access”. Without being given the correct access you'd technically be hacking the server, as it is specifically set up to restrict said access.


2 Answers

The origin of this issue was the custom authorizer which was generating a custom policy for a specific resource. As this policy was cached, when the second request arrives, it doesn't match with the one previously generated and returns an error.

Workaround: Disabling the cache

  • open the AWS console on the API Gateway service,
  • click on your API,
  • select Authorizers in the left pane and select your custom authorizer

In the Result TTL in seconds, type 0 and click Update. Now, you have to deploy your API to publish your changes :

  • click on the Ressources menu in the left pane and in the Actions dropdown menu, click Deploy API
  • select the stage and click Deploy

Solution: Improve your policy

def generatePolicy(principalId, context):
  return {
    'principalId': principalId,
    'policyDocument': {
        'Version': '2012-10-17',
        'Statement': [{
            'Action': 'execute-api:Invoke',
            'Effect': 'Allow',
            'Resource': 'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/*'
        }]
    },
    'context': context
  }

You can be more precise in the Resource property with an array:

'Resource': [
  'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/GET/projects',
  'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/GET/user',
  ...
]

You can either Allow a superset of ressources and Deny specific ones.

Have a look on @Jeremiah 's link : https://forums.aws.amazon.com/thread.jspa?threadID=225934&tstart=0

like image 74
Sylvain Avatar answered Oct 26 '22 04:10

Sylvain


So it appears the policy in the custom authorizer is generated for a very specific resource. This thread explains it - https://forums.aws.amazon.com/thread.jspa?threadID=225934&tstart=0

like image 29
Jeremiah Avatar answered Oct 26 '22 02:10

Jeremiah