AWS API gateway security for api keys - amazon-web-services

I am making a survey creator website that will have companies as customers. Companies that want to conduct market research by creating surveys.
I want to implement an api that allows those companies to make their survey results public if they choose to do so. I am using AWS Cognito for login/sign ups and API gateway paired with a lambda function for the api endpoint. The survey responses are stored in dynamodb.
My frontend application is in vue and it communicates with the backend which is spring boot, which means only spring boot talks to the aws services directly. I have a lambda function that fetches survey results from dynamodb given a user_id which is the company id (the sub claim from Cognito) and a form id.
My plan is to programmatically generate api keys when a public user (Not an IAM user or any user involved with the company) asks for access to the survey results of a company on the platform (results of a survey the company has decided to share with the public) but I can't seem to find a way to set specific permissions on api keys in API gateway so that a public user cannot just change the request parameters (company id and form id) and query for other data that is not supposed to be publicly available (the data of other companies and their surveys).
I have also looked into generating signed urls for api gateway but I can't find any code examples online for java.
My questions is what is the best way to go about protecting my api endpoints in this scenario?

Related

Usage of ID tokens and Access tokens, with external Authentication, AWS backend and graphql language

I am currently working on building a mobile app which will require the users be authenticated, and have them specific privileges on what they can do (for example, a logged in user will only be able to manage some of their data held in the backend database).
I think I do understand the differences between ID token (user identity) and Access token (for authorizing between the mobile phone client and the back-end), but I am not sure what I intend to do conforms to the best practices regarding authentication and authorization.
Let me summarize what I am planning to do:
front end will be a Flutter/Dart mobile app
authentication will be done through Google Firebase Authentication service
my back end will be hosted in AWS:
API Gateway will serve a unique graphQL endpoint
API Gateway has an associated Lambda authorizer function which processes requests prior to the actual "application" Lambda functions
"application" Lambda function serves GraphQL requests (using python ariadne library), including authorization business logic
Database is a managed PostGreSQL inside AWS
The authentication / authorization workflow is as follow:
Not all of this has been implemented yet, but on the paper I think it could work.
However, it goes against several good practices regarding token usage:
the ID token is sent along an API call which is advised against (see this nice auth0 blog post)
I make no usage of access token between the front end and the back-end (could the AWS policy generated at step 5 fullfill this role?)
I do not leverage the audience claims in tokens
Note: as GraphQL exposes a single endpoint, I am not sure of what the content of the access token should be
I am new to Authentication / Authorization and would gladly have some insight regarding the best way to actually make everything work as per best practices, accounting to the following contraints:
authentication is outside of AWS
the APIs are GraphQL

Capture and Store information of customer associated to API Key generated by api gateway

I have couple of api's built using api-gateway. I want to secure one of the end points using the api-key feature in api gateway. I am able to do that
I also want to capture customer details (like name, email) which is needed in the business logic of the api as well. So based on the provided api key, I should be able to pass customer email to the api(lambda).
But there is no scope of storing customer's information in api gateway.
Can someone help, how this can be achieved.

AWS Amplify/Cognito Tenant Selection at login

I am currently using AWS Cognito and it's hosted UI to manage user login. All my users sit in a single pool, which has a number of different app clients registered. Our users are grouped into different organisations and for the most part a single user (or email address) is only associated with a single organisation, so this setup works very well. A small subset of users are associated to multiple organisations. Associated to a particular organisation is managed by a backend service rather than using Cognito attributes and/or groups.
We are already using the pre token generation Lambda trigger to inject claims into our tokens to denote which organisation a user belongs to which is then used downstream in our backend services to control which database is hit when a user makes an API request (we use single tenant databases).
I need to design a mechanism that will allow the users who belong to multiple organisations to select which organisation they want to login as (ie select which tenant they want to use for that session) at auth time. I know this will be impossible to do with the Hosted Cognito UI but I'm wondering if this is something that can be done with AWS Amplify along with a custom login app and using custom auth challenges. The flow would be something like this:
Username/password provided
Custom auth challenge lambda fires which detects whether the user has a 1-1 relationship to a single organisation (in which case we can log them straight in) or a 1-many relationship to multiple orgs.
In the latter case above, the auth challenge returns a collection of organisations that a user is allowed to log in to back to the app which displays them in a picker control (drop down or similar)
User selects their tenant and this information is sent to the auth challenge response and the login continues.
A key step after this would be ensuring that the custom challenge responses make it through to the pre token generation Lambda function so it knows which organisation the user is logging into.
I'm a backend developer and have had no exposure to Amplify at all, I just need to know if this is theoretically possible before I invest too much time into it.
Can anybody with Amplify experience confirm if what I describe would be possible using Amplify and a custom auth React app?
Thanks

Suggestion: Integrating Amazon Cognito with AWS DynamoDB

I've built an application which is connected with Amazon Cognito to take the sign in and sign-ups of users. Currently, application support three different subscriptions (Free, Basic, Premium). If the user signs in for basic Subscriptions, I want to give them least access to DynamoDB for download the parts of applications which is required to run the application service.
How to connect DynamoDB with Cognito directly
I am not sure, what's the best approach to follow this scenario?
(Please note- this is not a mobile-based application, so do not give suggestion to use AWS Amplify or relatable services)
When I was first learning about Cognito, I had made the same set of assumptions you are currently making. I knew that User Pools could act as my application's user directory, and Identity Pools would magically unlock all my authorization needs. I was mistaken :)
At the risk of oversimplifying, AWS Cognito exists to answer two questions:
Who are you? (authentication)
What can you do? (authorization)
Cognito addresses these concerns with two distinct offerings: User Pools (authentication) and Identity Pools (authorization).
At a high level, User Pools let you handle user registration, authentication, account recovery, and supports authentication with third-party identity providers like Facebook, Google, etc. Sounds like you might have this part figured out.
Cognito Identity Pools, on the other hand, provides a way to authorize users to use various AWS services. You can think of it as a vending machine for handing out AWS credentials. For example, if you needed to give your users access to upload a file to an S3 bucket or to invoke an endpoint in API Gateway, you could do so with an Identity Pool. You can even allow item-level access to DynamoDB based on an Amazon Cognito ID. However, this might not work the way you expect since your application users are probably not directly connecting to DynamoDB.
In most web/mobile applications, users are not connecting directly to DynamoDB. Instead, they are interacting with a web/mobile app that communicates to the back-end of your application via an API. That API would then communicate with DynamoDB. If your stack is in AWS, the path may look something like this:
Client (web/mobile app) <-> API Gateway <-> Lambda <-> DynamoDB
In this architecture, your users would authenticate via Cognito. Cognito would then authorize the user to make calls to API Gateway. API Gateway would execute your lambda, which would then interact with DynamoDB. The "user" of DynamoDB in this example is your Lambda, not the user of your application.
That last bit is important, so I'll repeat it: Unless your users are directly connecting to DynamoDB (not recommended), they are not the "user" operating on DynamoDb. Therefore, restricting DynamoDB access based on a user's Cognito ID is not going to be an option for you.
So, what can you do? Your application needs to provide the business logic around what effect your users can have on DynamoDB. Perhaps free users have read-only access to a specific partition, while premium users can modify the same partition. That logic has to be handled directly by you.
I know you said you weren't looking for Amplify suggestions since your application is not mobile-based. However, Amplify offers SDKs that aren't specific to mobile development. The folks at Serverless have made a fantastic tutorial on building a full-stack serverless web app, which includes a very readable chapter on serverless auth with Cognito. They use Amplify in a web app to integrate with Cognito, S3, and API Gateway. If that's something you are trying to do, I'd recommend checking it out.

AWS Feature based licensing

I am designing a product which would be deployed to AWS. It will use Cognito for user authentication. It will be a multi-tenant application.
The application has many modules/features. The pricing depends on the features selected by the client.
Please provide guidance on how can I implement a check if the feature is licensed or not. I don't want to put the logic inside each web api endpoint.
You should create an application microservice (callable via a API, but with access locked down to your own application) that receives information such as:
Authenticated User ID
Service wanting to be accessed
Resource-level information in case you want fine-grained access control
The authentication microservice would consult a database, apply appropriate business logic and return a success indicator.
Preferably:
Each request should be logged in an audit trail
If access is denied, return an error message that could hint at the reason why (eg 'This feature is requires subscription to the XYZ module')
Use some form of cache to make the queries super-fast (eg DAX for DynamoDB, or ElastiCache)
Licensing systems can often be more complex than actual applications!