I have set up an API GW with multiple resources, one requiring an API Key and the other one not requiring an API Key as shown below.
The Swagger resource is configured to not need an API Key, while the other resource has been set up to require one.
The API is deployed to a stage using a usage plan which has an API Key attached to it.
With this setup, however, I see that unless I pass a valid key in the header for the Swagger resource the call fails with 403 forbidden.
Did I miss a step somewhere?
Related
So I tried finding out about this in general (on a conceptual level but still not many results).
What I want is that different users will be provided with a public API and they can only use it if they have their API key (a common thing done by many existing products/companies).
I read that we can create a custom API key on the API gateway which we then can pass along with the headers or query params and it can be verified either via Cognito/Custom Lambda Authorizer, but according to my understanding that is the only API key which will be shared by all users.
I want each user to have their own API key and use that every time they want to make a request through the API.
I read about creating custom API via API gateway on the AWS console itself or configuring Serverless.yml and adding private:true in lambda config and while deploying it will generate an API key (but again this is not user-specific, so any user can use this to make calls to the API). (Referred to this video here)
Also, I have used Cognito as an authorizer but there the flow was different in the sense that the user logged in and got an ID-Token which I used as authentication (which gets expired too). But here I want just to generate an API key that users can simply use anytime and anywhere.
Let's say I have an AWS API Gateway. I have a resource in said gateway that requires the use of a gateway API Key. I would like my server to know which of my various keys are being used to authenticate (just for logging; there's no access control happening based on this).
How do I include the name of the gateway API Key in the request that is being sent to the server?
Firstly, you mentioned logging which keys are used for authentication. API GW API Keys are intended to be used with usage plans, not authentication/authorization (link).
For user authentication and authorization, don't use API keys. Use an IAM role, a Lambda authorizer, or an Amazon Cognito user pool.
I think it is because of this reason, AWS does not forward the key further to the backend. Furthermore, if you have used one of the authorizers like Lambda or Cognito, your backend will have a way to log the authenticated identity.
If you really want to log the API keys though, I think you can use a mapping template to explicitly tell API GW to forward the x-api-key header.
API keys attached to an API gateway have to be unique. From the docs:
API key values must be unique. If you try to create two API keys with different names and the same value, API Gateway considers them to be the same API key.
The is no such header to specify the name of the key. You can create your own custom header where you would add this information, but nothing would guarantee that the correct name is sent with a given API key. You would probably want to implement a call using the AWS SDK from your server to retrieve the name of the API key.
In case you are using a Lambda authorizer function, you can fetch the name of the API key in this function and forward it as a header to the backend server.
We have deployed a Chalice app to AWS, and we are receiving the following response when calling endpoints that require an API Key:
{
"message": "Forbidden"
}
Endpoints that don't require an API Key can be called without any issues.
What's strange is that we used to be able to call the endpoints that require an API Key without any issues, so we're also considering a Chalice or AWS update to have caused the issue.
We're using Postman are passing the API Key as a Header in the request:
x-api-key: Our API Key's Value.
We're also not getting any logs in CloudWatch, presumably because the endpoints aren't actually getting called due to the issue. AWS is blocking the request before it even reaches our endpoint.
Our API Key has been configured as follows:
API Key:
ID: Our key's ID.
Name: Our key's name.
API key: Our key's value.
Enabled: Enabled
Associated Usage Plan:
ID: Our plan's ID.
Name: Our plan's name.
Throttle: No throttling.
Quota: No quota.
The API Key and Usage Plans look properly configured, so we assume the issue is not with the API Key itself.
From the "Troubleshoot API Gateway 403 Forbidden errors" documentation:
If the API Key was invalid (or, we assume, incorrect), we would be getting the below message instead:
"Invalid API Key identifier specified"
However, we are getting the generic "Forbidden" error instead:
"Forbidden"
The documentation only lists three possible causes for this error:
The request is blocked by web application firewall (WAF) filtering when AWS WAF is activated in the API.
When invoking a private API from within an Amazon Virtual Private Cloud (Amazon VPC) using public DNS names, the "Host" or "x-apigw-api-id" header is missing in the request.
The caller uses the default execute-api endpoint to invoke a REST API after disabling the default endpoint.
We believe that none of the above reasons apply to us due to the following:
We don't have a WAF (nor Web ACL) configured in our API Gateway.
We're not invoking a private API from within an Amazon VPC.
We did not disable the default endpoint and are instead using the default Invoke URL.
Did we miss something, or could this be a Chalice or AWS issue?
We found the source of the issue.
Apparently, the Usage Plan that our API Key was tied to was configured for another API.
All we had to do was add our API to the Usage Plan's Associated API Stages.
I have an aws api gateway api that was using a api key to authenticate requests. It was tied to a usage plan and it was working. Later we needed a new api key name and value. I removed the old api key from usage plan and added the new api key to usage plan. Re-deployed the stage. Now when using the new api key name and value in the header the requests always return as 403 forbidden. Not sure what is wrong. Everything looks right.
The header for an API key must be x-api-key, without this the API will return a 403 when API key authentication is enabled for the stage.
You distribute API keys to your customers and require them to pass the API key as the X-API-Key header of each incoming request.
The name of the key does not need to share this, in fact you can use it to describe the application/user who will be using this API key with your integration.
To call your API you would use the below where $key is the API key value.
curl -H "x-api-key: $key" https://xxxxxx.execute-api.us-west-2.amazonaws.com/get-token
You can find out more information about this in the Choose an API key source documentation.
I have a serverless backend that operates with APIGateway and Lambda. Here is my architecture:
Currently, anyone with my APIGateway's URL can query or mutate the data. How do I protect the URL, so that only the client(react app) can access it. So, here is my concern, anyone can open the network tab in chrome console and get my APIGateway's URL and can use it using curl or postman. I want to prevent that.
Solutions I had in my mind:
Set up a CORS, so that only the origin can access it. But, I have a different lambda that invokes this URL. So, CORS wont work out.
I am sure there are some methods with the APIGateway itself. I am not getting right search term to get it from AWS documentation. I would also like to know what are the best practices to prevent accessing the backend URL apart from the Client(React App)
Update after #Ashan answer:
Thank you #Ashan for the answer. In my case, I use Auth0, so custom authoriser should work for me. I just came across this https://www.youtube.com/watch?v=n4hsWVXCuVI, which pretty much explains all the authorization and authentication possible with APIGateway. I am aware that authentication is possible either by Cognito/Auth0, but I have some simple websites, that has form, whose backend is handled by APIGateway. I can prevent the abuse from scraping bots using captcha, but once the attacker has got the URL, header and request parameters, he can invoke that million times. One thing, we can do is having an API-Key, but it is a static string with no expiration. Once the headers are with him, he can abuse it. So, any idea, how to prevent this in APIGateway. If not any other service apart from AWS that I can look for? Would be glad, If I get an answer for this.
Currently API Gateway does not support private urls, so it will be publicly available.
To restrict access you need to use a authorizer to authenticate and authorize the request using IAM policies. There are two options available at the moment.
IAM authorizer
Custom authorizer
If your authentication flow can directly (AWS STS, IAM user access keys or roles) or indirectly(Using AWS Cognito Userpools or any other SSO provider) can get temporary security credentials, then you can use IAM authorizer. From API Gateway side no code involved and its a matter of selecting the IAM check box for each API Gateway resource. You can use the API Gateway SDKs to invoke API Gateway requests where the SDK will handle the heavy liftings in setting up authentication headers.
If you use your own authentication mechanism, then you can write a seperate Lambda function to validate the tokens. This Lambda function name can be specified at API Gateway with the http hearder name to access the custom token to verify the requests.
To control API usage by authorized consumers, using API Key is the only way native to AWS at the moment.
Since you are using S3 for the react app hosting, you can further reduce the attack surface by using AWS WAF and CloudFront infront your application stack. The API Key can be added to CloudFront headers to forward to your APIGateway origin and since CloudFront and APIGateway communication happens using SSL, its nearly impossible for someone to find the API key. Using AWS WAF you can limit malicious access for common attacks. This includes rate based blocking to limit someone from repeatedly invoking the API.