Hello guys I have written an AWS lambda function which should be open to all. I have configured my cloud front also which will be accessible to users. How can I make the API gateway to take requests only from the Cloud front or whitelist the cloud front domain. Something like Allowed_hosts.
I should not be able to respond to any calls from the postman or any such tools. API gateway should only respond to calls from cloudfront.
How can I do this ?? I dont want to have the authentication system setup like Congnito or IAM.
Is there any better method to do this ??
I have looked at CORS and Access Control Allow Origin. But these are browser based.
I need a method which will accept calls only from cloud front or my s3 bucket. Not from localhost or postman etc.
Thanks In advance.
Step 1:
Setup API Keys with API Gateway.
https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-setup-api-key-with-restapi.html
Step 2:
Add API Keys to CloudFront Origin with a custom header.
If anyone calls the API Gateway without a valid key, it will get refused.
To setup authentication on CloudFront you can sign the urls.
Hope it helps.
I do not think that there is a way to restrict calls to your API GW endpoints... However, you can use the so-called API Keys. When you make a request to the specific API GW endpoint, you need to provide a header x-api-key and the corresponding API Key as a value. As long as you provide the header with correct value, you will be able to access the functionality behind your endpoint. If you do not provide a correct API Key, you will simply get 403 Forbidden.
Please take a look here and if you have any questions, read through the documentation. It's quite clear.
If there is anything unclear in my answer, I am open to help!
Cheers.
Related
I'm looking after solution where AWS Api Gateway changes method endpoint Url dynamically.
I am familiar with stage variables and in Integration request I can change endpoint per method like (https://${stageVariables.Url}/api/DoSomething).
What I need is that information how parse endpoint is included in requests.
https://${RequestData.Url}/api/DoSomething
I have same Api in different locations and to implement centralized Api keys and logging services I try to forward all traffic through this one Api Gateway.
After first request client gets its endpoint information, but I don't know how to solve that clients next requests to Gateway should forward to that endpoint which client get earlier.
I got an answer from AWS support. They told that I have to make a lambda function to process all requests or just use Stage variables.
I'd like to add a default throttled API key for unauthenticated requests to prevent abuse.
How would I do this in API Gateway?
EDIT
To make it clearer what I need, how do I transform a request in API Gateway? Is this possible?
I would say using Cognito is the best way of authorizing API gateway.
If you want a default API key then you can go for custom API gateway authorizer. Please have a look on official documentation for the same here
You need to store the API Key in the Server Side of your application and shouldn't expose it to the Client Side (Although API Key is not considered as a security token, it can be used by malicious party to call your API).
There are couple of options you have based on the nature of your application consuming the API.
If it is a single page web application where front-end is hosted in S3, you can use AWS CloudFront to store the API Key in headers and forward it to the API Gateway, while also serving the frontend through the same CloudFront distribution. This will also remove the cross origin resource sharing problem between your web application and API Gateway.
If you have a web server, you can store the API Key at Web Server and use to proxy request to the API Gateway while setting the API Key header value.
Note: Don't use API Key for authentication which is not recommended.
This is how I would solve it.
Create Usage Plan with the throttle, burst and max limit on the request allowed.
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/APIGateway.html#createUsagePlan-property
API Key:
Create API Key (createApiKey) and associate it (createUsagePlanKey) with Usage Plan already defined. That will allow the limit defined for the requests received.
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/APIGateway.html#createApiKey-property
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/APIGateway.html#createUsagePlanKey-property
Have a separate lambda to monitor the Generated API-Keys and cleanup once it is expired, so you will not flood API-Gateway with unused keys.
If you take it to CloudFront, you can create Self Signed URL, that will be valid for a given period of time. After that time limit URL will be invalid. This is to keep yourself time-limited for the user, so within the given timelimit, what resource they can access.
One more usecase, we worked on, you can authenticate the user only on certain urls with custom Authorizer. Any other urls that get invokes, will return unauthorized without any additional code.
Hope it helps.
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.
So my problem is I have a lambda function created in AWS Lambda and is linked to the api gateway. So I want to make sure the request to the lambda function only happens throug my domain www.example.com
In this domain I make a request to run the serverless lambda function to perform a specific task.
Is there a way to ensure the api request is accepted only from my domain or host.
Also I make use of Python 2.7 to write the lambda function if there is any alternative please do suggest me, I am new to python and AWS Lambda.
If you are worried about browsers making requests to your api on www.example.com, that shouldn't happen if you don't have CORS headers that allow other domains to make requests. But outside of a browser, anyone can still make requests to your APt.
You can however authenticate api calls. This can be a simple api key thats on your client or temporary credentials (call STS to get credentials for a role) to call your api. But with effort someone (look at your source code and replicate the calling mechanism) can still call your api. You could increase the level of effort required, if you only allow authenticated users (authenticated using some name/password and enforced on api gateway) to make api calls.
If you are worried about being over billed, you can setup a usage plan on your api key and restrict it to x number of calls a day/week/month.
API Gateway supports multiple authentication mechanisms
IAM Auth https://aws.amazon.com/premiumsupport/knowledge-center/iam-authentication-api-gateway/
API Key http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-setup-api-key-with-console.html
Cognito user pools http://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
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...
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.
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