AWS API Gateway - Using custom API endpoint for authorization running always on an EC2 instance - amazon-web-services

We are planning on setting up an AWS API Gateway. We also have a requirement that every call that hits our API gateway should go through a JWT token validation. We are using Okta as our IDP which will generate an access token.
We tried AWS REST API gateway which supports lambda authorizer but the problem we have with it is that lambda's are too slow and there is no way we can cache the JWKS URI and keys. We would get 1000's of requests within a second and lambda's does not work well here. Our goal is to achieve token validation within 2 digit milliseconds which is only possible if we are able to cache the JWKS public key and refetch it only when it is rotated. Please note we do not want to use the caching option of REST API to cache authorization.
We also tried AWS HTTP API which support JWT authorizer but even here we are getting only 3 digit millisecond performance like 500ms-700ms. The majority of the time is spent on fetching the OIDC metdata endpoint and fetching the public key from okta issuer endpoint.
Now, we know that the we could implement our own custom token validation (Authorizer) within one of our own REST API service (Using golang or nodejs) that will run always within an EC2 instance or fargate server within an ECS cluster or for simplicity just within an EC2 instance.
Does AWS API gateway by any chance allow some kind of custom hook where whichever endpoint on the gateway is invoked it should first invoke our custom REST API endpoint which is running in an EC2 instance and then once it gets a valid token response it should invoke the actual URL. Is this even possible? If not, what other options do we have.
Thanks

Related

Do I need to verify a AWS Cognito token in BOTH Lambda AND as API Gateway?

When using a AWS Cognito attribute from a JWT token in a lambda, do I need to verify the JWT? The Lambda is only triggered by an API Gateway which already verifies the token.
Adding details:
- I'm using Cognito Authorizer in the API Gateway to verify the token.
- The lambda is connected to the API Gateway as proxy.
No you don't need to verify the JWT in backend lambda if protected by a custom lambda authorizer by API Gateway. I would suggest you to use REQUEST based lambda authorizer and attach attributes in the response. So your backend lambda will be able to access attributes in event.requestContext.authorizer['your_attribue'].
This will also enable you to test your Lambda in isolation without needing to get attribute from JWT. You can always mock the event object for unit testing.
I ran into the same conundrum, and was trying to find documented confirmation that, within the Lambda, I wouldn't have to do any validation on my own, and that I can safely rely on the the token / claims being genuine. Unfortunately, nothing in the AWS documentation or the forum posts that I've seen so far has explicitly confirmed this.
But I did find something similar for GCP, and how the API Gateway there validates the JWT. From the GCP documentation:
To authenticate a user, a client application must send a JSON Web
Token (JWT) in the authorization header of the HTTP request to your
backend API. API Gateway validates the token on behalf of your API, so
you don't have to add any code in your API to process the
authentication. However, you do need to configure the API config for
your gateway to support your chosen authentication methods.
API Gateway validates a JWT in a performant way by using the JWT
issuer's JSON Web Key Set (JWKS). The location of the JWKS is
specified in the x-google-jwks_uri field of the gateway's API config.
API Gateway caches the JWKS for five minutes and refreshes it every
five minutes.
So, it seems that within GCP at least, we don't have to do anything, and the API Gateway will handle everything. Even though this is not a confirmation that this is how it works in AWS as well, but the fact that this is how it works in GCP, it gives me some more confidence in assuming that it must be so in AWS too.

Using AWS API Gateway for Lumen based REST API Service with Passport authentication hosted in EC2

I am entirely newbie in Amazon Web services. Currently i am developed a REST API service using Laravel's micro frameworks called Lumen. I am using passport for token based authentication and all that working fine. I need a proxy server to hide my actual endpoints and do some other functionality so i am planning to use AWS API Proxy Gateway and host the API endpoints in EC2 instance.
i went through Build an API with HTTP Proxy Integration from Aws documentation. but there is nothing about using a custom authentication using Oauth.
My Doubts are
How to use Passport authentication when using AWS API Gateway
Is there any good method to hide my REST Endpoint from customer and need a way to change the proxy end point from time to time.
I don't know Laravel ecosystem, but:
if passport expose something like an OpenId Connect you could use Cognito Federated Identities for, precisely, federate your identity, and associate the authorized identities with a given IAM role and unauthorized with another role;
you can use an Api Gateway Custom Authorizer to perform fully customizable auth;
Try expanding your question so we could add more details...
Yes, like what BAD_SEED said, you can use API Gateway Lambda authorizer (formerly known as the custom authorizer) to do any logic to verify the token, since it's just a javascript package.
So, one option is like what auth0 does in (https://auth0.com/docs/integrations/aws-api-gateway/custom-authorizers/part-3) and (https://github.com/auth0-samples/jwt-rsa-aws-custom-authorizer). Their sample authorizer does followings:
It confirms that an OAuth2 bearer token has been passed via the Authorization header.
It confirms that the token is a JWT that has been signed using the RS256 algorithm with a specific public key
It obtains the public key by inspecting the configuration returned by a configured JWKS endpoint
It also ensures that the JWT has the required Issuer (iss claim) and Audience (aud claim)
But unfortunately, Passport does not support JWKS endpoint (which exposes public key for the token signature). So you may have to expose it by yourself.
Another option is much easier, you just make a token verification endpoint in your application, something like /users/me, and protect it with auth middleware. Then in your Lambda authorizer, call it with the token in the request to your other micro service endpoints. By this way, all token verification stuff is left to Passport, and the authorizer just executes policy based on the result of the verification.
Not very sure about what you want to reach, but API Gateway is just a proxy, so you can certainly change backend side endpoints for its frontend one, which is better not changing so often.

How to add default throttled API key for unauthenticated API Gateway requests to prevent abuse?

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.

How to secure the APIGateway generated URL?

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.

Saving some info as a session in API Gateway or lambda

I am going to design a single sign on website and in one component of my project I am using API Gateway. API Gateway is responsible to direct the to the appropriate services based on the user status so if the user is valid(the token sent from user is not expired) the related service for getting what he is requesting will be serve and if the token sent from the UI is expired then he will be sent to authorization service first. So as you noticed I need to save the tokens and their expiration dates somewhere in API gateway. Is there anyway I can achieve this via API Gateway? if not can I use lambda function to achieve this?
API Gateway and Lambda are stateless services.
You need to make use of some other persistent storage on AWS like
DynamoDB or RDS or Elasticache and call it from the Lambda function in order to implement the desired functionality.
You may also want to take a look at API Gateway Custom Authorizers on how to implement this functionality on API Gateway, using a lambda function.
I would implement a DynamoDB table and set the TTL expiry as the token expiration. That way you don't have to manage the deletion of the records. You can enhance your authentication system to add the token entry to this table.
You might be able to accomplish this with an API Gateway custom authorizer.
Walk Through of Using Custom Authorizers in API Gateway Documentation
Blog Post Introducing Customer Authorizers