I have moved my microservices behind AWS Api Gateway and have secured it with oAuth 2.0 using AWS Cognito, As per my implementation the client first have to call the cognito url to get the access token, then they will call Api Gateway with the access token to reach till the desired service.
My question is that, should i also move cognito service behind Api Gateway or should i leave it as is, what would be better both in terms of billing and security. Expert Advice required.
This is my first implementation with Aws so please bear with me if the questions sounds stupid.
AWS has a blogpost where they explore a Cognito setup combined with API Gateway. You can read it here. This image is an excerpt of that blogpost:
As you can see, the Cognito infrastructure is not placed behind the API Gateway, but rather in front of it. A good reason for this is to not incur charges for API Gateway when your users are not even able to pass through cognito.
But, this is not a rule. API Gateway offers advantages that could make your life easier, as the OP has pointed out. For instance, API Gateway can impose rate limiting, next to other features.
Related
I have a RESTful API being accessed via AWS API Gateway. I want both human users (authenticated via Cognito) AND other (internal) services to be able to call the API. There exists plenty of documentation of how to do either, but not for how to do both.
I have tried using unauthenticated Cognito federated identities to authorize services. I have also used Cognito user pools to authenticate people. However, API Gateway only allows for a single authorizer (in this case, either AWS_IAM or a Cognito authorizer). However, I don't see a way to do both.
I imagine I will need a custom Lambda authorizer, but I'm having a lot of trouble finding accurate information on how to write an authorizer using IAM or Cognito.
Surely we can't be the first people to want to allow both services and humans access to an API. The dearth of documentation on doing so leads me to believe I'm either missing something painfully obvious or that this is a use case that is best avoided (in which case, what IS best practice?).
Is there any way of doing both? Is there a Lambda authorizer example that can point me in the right direction? Is there something built-in that I'm missing?
We have rejected the idea of "pretending" that a Cognito user is a human, when in fact it's actually a service, as it seems to us to be a misuse of Cognito user pools and identity federation. Likewise, the opposite, where a Cognito user is federated to act as an IAM role shared by both users and services, seems like a misuse of user authentication.
Is there a canonical way to do this? If not, is there existing documentation of how to write a custom Lambda authorizer to do both?
The short answer is: you (probably) don't need to use API Gateway for either case.
API Gateway, as the name suggests, is just a gateway. It takes a request (often HTTP) and forwards it to another location (a Lambda function, an EC2 instance, another AWS service, or another HTTP endpoint). This is great if you need users who do not have an associated IAM role to access AWS services.
Users who are authenticated through Cognito have an associated IAM role through the associated Cognito Identity Pool. Just give them access to the AWS services this way, no need to go through API Gateway.
AWS services that need access to other AWS services don't need to go through API Gateway, they need to be given permission through their IAM role.
If for some reason you must use API Gateway for both your users and your services, make two API Gateways that point to the same resources that use different authentication methods.
Recently I have been working with AWS API gateway where I created an API and protected it with API key and Cognito (OAuth).
One day I found that my API has been accessed 10K times which failed because of attacker didn't had the access to it.
My question is : Does Amazon charge for such api calls which are unauthorized? If they charge then how to protect it. As I understand even if I put WAF in front it my API url will still be exposed ....
Any help is appreciated...
If you protect your endpoint with the following authorization types: AWS_IAM, CUSTOM, and COGNITO_USER_POOLS, API Gateway will not be charged for failed requests. Please reference the Pricing Documentation. Also reference Secure AWS API Gateway with Lambda Integration
What you are describing is a type of DDoS attack.
This is what you need to do to protect your API Gateway Endpoint from DDoS attack.
1) Create your API
2) Setup CloudFront distribution to your API
3) Front your CloudFront distribution with AWS WAF.
4) Create ACL rule and set requester limit to what you deem appropriate.
5) Test.
You still need to use AWS_IAM or Cognito to do the authorization part.
Here is the document that details the steps:
https://aws.amazon.com/blogs/compute/protecting-your-api-using-amazon-api-gateway-and-aws-waf-part-i/
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.
I have been making a web app. (Angular 2 on S3 and APIs in lambda through API gateway). For authentication I played both with cognito and custom authorizer (I configured my authentication to work with Google and Facebook bith via a custom authorizer and cognito). In case of custom authorizer I am passing a token via authroization header and my custom authorizer validates it.
I am looking for advice on which should I go forward with and what are their pros and cons. Ones that I could think of are:
AWS cognito:
Pros
AWS SDK handles everything for you and you cannot make much mistake in your authentication process.
Fine grained access control for AWS resources via IAM.
An extra lambda function in front of every API is not required for authentication.
Cons
Need to use AWS SDK specifically on client side. Programmers have to add this into their toolchain and make use if it during development. Adds extra complexity.
Fine grained access control for resources is not really required since the only access that is required is for API gateway.
Custom authorizer
Pros
You can have your authentication mechanism the way you want it. Ultimate control over authentication and authorization.
You can have the UI call the APIs with a standard token (JWT) and the flow for developers remains same. No extra consideration of AWS SDK.
Cons
Authentication requires a lot of thinking and effort to build.
Chances of missing some crucial aspects are always there.
Its like reinventing the wheel. Why do it when Amazon has already done it for you.
All that being said, I am leaning towards custom authorizer for now. Need advice here on the topic.
PS: I know there cannot be a definite answer to the question I have posted but it would be of great help to people trying to decide on authentication for their applications.
okay, authentication and security is indeed hard and there are a lot of issues that have been thought about and taken care by AWS security team that you may not think of and implement and make your application insecure. I implemented my custom authorizer to expect an authorization token (passed through authorization header) that was a base64 encoded value which would repeat across all the requests in a session. It turns out that due to weaknesses in RC4 and diffie hellman this makes the TLS susceptible to attack. If we simply use cognito using IAM then AWS sigv4 request signing protects you from these weaknesses. Watch https://www.youtube.com/watch?v=zmMpgbIhCpw for more details.
Another benefit of using cognito/IAM is that it protects you against CSRF replay attack. Request signing involves using timestamp. IAM will deny any requests that are signed more than ~5 minutes ago.
In short avoid using custom authorizer if you can and use IAM with cognito. You will thank yourself.
This is a short answer but, why not use both of them?
Use a custom authorizer that is actually implemented to use Cognito Users Pool and Cognito Federated Identities.
When you use Cognito you can make the choice not to use everything.
For example I set up a custom Authorizer and my Lambda is actually using Cognito Users Pool API to authenticate the user. I let Cognito Users Pool to handle all the passwords, tokens, etc..
This is bit tricky situation I got into here,
I set up a lambda function & API gateway, then I setup cloudfront over API gateway for faster processing and achieving benefit of all the endpoint nodes provided by AWS [It should take more time using cloudfront on top of API gateway service but I am getting better result with cloudfront layer on top of it, maybe DNS resolution and AWS internal infrastructure is better]
I setup a JAVA function inside lambda which is working perfectly fine, but I want to use Context of request maker in lambda function
public String handleRequest(UserPOJO input, Context context) {
}
If I make direct lambda function request I can achieve that but it's taking too much time executing direct lambda from my Android client, also I don't find it good to expose those details, and with cloudfront I am not sure what headers should I send so that lambda detects it's cognito role and ID using context.getIdentity().getIdentityId(); in lambda.
If someone understands my problem here and elaborate it better for other I will be glad, it is very complex to explain the problem.
Technically
I can make execution of lambda function directly with cognito credential provider authentication but Very slow
Can make API gateway request which cognito credential provider authentication, speed is better than direct lambda execution
Can make cloudfront request but stuck where I don't know how can I use cognito credential provider authorisation while making the request. Seemed faster than API gateway.
Thanks. :)
If you want to get Cognito related information in Lambda function and you are proxying your request from API Gateway, You can use the mapping template to include information you need, then you can get it from the input object.
I can make execution of lambda function directly with cognito credential provider authentication but Very slow.
I recommend you to build your Lambda function in python or javascript runtime.
Can make API gateway request which cognito credential provider authentication, speed is better than direct lambda execution
API Gateway cannot improve the performance of your Lambda function, but API Gateway can provide API management feature for your Lambda function.
Can make cloudfront request but stuck where I don't know how can I use cognito credential provider authorisation while making the request. Seemed faster than API gateway.
CloudFront doesn't have do anything with your Cognito credential. It just passes everything it gets to API Gateway.
I am not sure how adding a CloudFront distribution in front of API Gateway can make the latency better except you enable the edge side cache which is not calling your Lambda function every time.