Limiting Number of Signups Per User Pool - amazon-web-services

is there a way to limit the number of users that are allowed to signup in Cognito per User Pool? The idea is to create a tier based plan that allows an organization to only be able to create a certain number of users (eg. basic plan - 3 users, pro - 10 users, etc...). I'm thinking of tackling this with the presignup trigger but I'm not sure if that's the way to go or if there's a better way to handle this.

From the Pre Sign-up docs:
The pre sign-up Lambda function is triggered just before Amazon
Cognito signs up a new user. It allows you to perform custom
validation to accept or deny the registration request as part of the
sign-up process
So far so good. But you may have challenges counting the number of users in the pool. The best I found was the ability to ListUsers and that could get expensive if you've got a large user pool.
In that case I would still use the pre-sign up Lambda but store the count of users somewhere. Perhaps a DynamoDB table or updating the user pool with a tag that has the number of users.

Related

AWS Authorizers

I am creating an app on AWS using API gateway, Lambda and DynamoDb which will be used as Helpdesk ticket tool. The tool should support thousands of users, hundreds of organizations. One of the requirements would be for an administrative user to create their own sets of roles (groups) that would then be assigned to users in the app. The roles will, of course, determine whether a user can access a url resource on the API gateway (or rather the Lambda function behind it). I think I've worked out that Cognito user pools are probably the best way to manage users themselves but there are some quotas on user pools that won't work so well for what I'm attempting using Cognita's implementation of groups (max 10k user groups which is less of a problem and max 100 user groups for a given user which is more of a problem). I already have a plan for this which seems ok: I can create a dynamodb table to hold group definitions (name, desc, list of roles) and a separate dynamodb table which maps users to groups.
I need to have an easily configurable way to restrict a user from being able to access a resource they don't have access to. Since I don't feel like I can use Cognito groups, then what I had intended to do was (part 1) just use the AWS IAM authorizer to authorize the user to hit the resource (of course this lets ANY authenticated user hit it), (part 2) to create a lambda function that gets triggered on PreTokenGeneration and inject a custom claim into the token which list the roles the user had access to. Once that is working, (part 3) then in order to utilize this custom claim, I'd intended to add a check on each resource to decode the token and check to see if the appropriate claim was present (so, for instance, if it is the lambda that gets triggered for POST on /tickets then the claim I would check for in the token would be to see if 'appUserRoles' includes 'TICKETS_CREATE'). This would just method call to a JWT utils function to decode the id token to check to see if the claim is present. If the token has the appropriate claim, then the Lambda would perform the put item on Dyanamo and return some result, if the token doesn't have the appropriate claim, the Lambda would return a 403.
I already have most of this working and I'm pretty confident I can get it all working but I'm less sure on whether this is the best or even a good approach. Is there a better / easier / more efficient / (maybe more secure) way to accomplish this?

How to restrict AWS Cognito users from taking certain actions?

Help is required in the following problem we're facing 😔
Any tip would be much appreciated!
Details and environment:
A multi-tenant application that aims to provide a dedicated tenant per customer (organization), in order to achieve full separation.
AWS Cognito user pool as my users' datastore and authentication provider.
an "AWS Cognito user pool" per customer (org).
Role management - based on the built-in user pool groups. Group per role and the server-side verifies that a user's access token includes a group name in it's embedded group's list.
So far so good and everything is working as expected, using AWS Amplify's SDK, for the client side's implementation. Amplify performs well and allows me to do whatever I want. The server verifies group belonging etc.
The problem:
I want to restrict non-admin users (that doesn't belong to the "admin" group) from performing certain Cognito actions via Amplify.
2 Examples:
I want to disable non-admin users' ability to modify a specific attribute's value, via Amplify.
I want to disable non-admin users' ability to modify MFA settings for themselves, via Amplify.
The actual problem started when I wanted administrators to be able to set MFA (enable/disable) for other users, but in Cognito (as I understand it) only a user can set his own MFA settings.
What I saw and already tried:
Set read/write permissions for user attributes. So the specific attribute I want to protect is modifiable only via API calls with developer credentials. That way, admins can call my server to ask for attribute modification. The server verifies the role by a group belonging according to the access token and calls Cognito API. The problem with that solution is that it covers only the attribute modification scenario.
Create an AWS Cognito identity pool for each of the user pools. For every group in every user pool, create an AWS IAM role with a policy that would restrict or allow the wanted behavior. The could actually work. The problem with that solution is that it feels like a super-duper overkill, plus it requires me to create an extra identity pool and an IAM role for each user pool. It means that every new customer that joins the service, would require (1) user pool, (2) Cognito client application, (3) identity pool and (4) IAM Role (instead of just a user pool and Cognito client app). Essentially, implementing this solution.
The real question:
Can I restrict users in a certain group from performing actions on themselves, such as disabling the MFA (even that the user-pool's MFA is set to "Optional")?
Thank you all so much! any help would be appreciated!
Well... After long research, we have come to the understanding that there is no proper right way. Every possible solution has its own pros and cons. A consultant meeting with AWS's experts taught us that:
Options Overview:
[Server Side Only] - Solution #1 that I proposed is exactly as described. Drawbacks are the same. It could work, and access to user-attributes will be restricted. Any other action that another client would make will not be blocked.
[Identity Pools] - Solution #2 that I proposed is the most accurate one. Yet I described it with one big mistake: one identity-pool can serve multiple user-pools! So essentially, we could create only one IAM role and one identity-pool per app's role. Then we match every user-pool we want to that same identity-pool and when introducing a new role to the app - just create a new group in the user-pool and match it to the IAM role. This solution is not as complicated as thought, and it would definitely do the trick. As a bonus, you'll get the ability to control and allow access to different AWS services. That being said, it still requires management and effort.
[Post-Auth Lambda] - Solution #3 that was not mentioned here, and I started to work on a day after posting this post. I blocked the write permissions of a new boolean custom attribute called "MFA". It indicates the desired MFA configuration for the user. Only a server could edit its value (and users with the admin role will have access to the server's API endpoint that can modify it). We've deployed a lambda function that would be triggered after successful authentication (post auth trigger in Cognito user-pool). It would verify a match between the desired and current MFA configurations for the authenticated user. If there is a mismatch, throw the user out because he did something that is not allowed.
*To be exact, we created one more custom attribute called "mfa_status" and it is set to true after the user has set it's MFA configurations. The lambda checks if both MFA and mfa_status are true and the real current MFA Configurations are false. if this is the case - the user is thrown out.
The Chosen One:
The solution we picked eventually is #3 (Post-Auth lambda) as it is the most detached solution. It does not require any mix with our server or client's code, any special configurations that are specific to a user pool and it still allows us to keep working with the Cognito's Amplify SDK as a client.
Thank you all for your time, I hope this post would help someone in the future.

Best way to synchronise RDS DB and Cognito

I'm pretty new in all the AWS Tools BTW. Anyhow, I already created the Cognito User Pool and I can create and login new users but I also need those fields in my RDS database.
Yesterday I was reading docs and tutorials about the problem but looks like there is a lot of ways to synchronise two data sources. I don't know if something like AppSync has the options to do that or I need to write a two steps lambda, so I'm looking for advice for more experienced users like you guys.
You can have only the basic required attributes for authentication in the cognito user pool such as username, name, email and phone number and the rest of the meta data in some other database such as RDS or DynamoDB.
Within dynamo or RDS you can create a one to one mapping of the username in cognito and the rest of the metadata. Like for example:
*username* -> pk
employee_id
address
user_type
first_name
last_name
marital_status
gender
From implementation point of view:
Expose lambda to create and update a user. Create a user in cognito using only the required attributes earlier defined using the cognito APIs, next insert the meta data for that user in the database of your choice. Same goes for your PUT API with a slight change that you will have to update user pool and user meta data in the database.
Short answer:
You can replicate Cognito User Pool data to a SQL table by listening to Cognito events (using AWS Lambda, for example).
Long answer:
I think you can have Cognito User Pools as authentication/user data Bounded Context, in other words a single source of truth for authentication and user data.
And other BC's in need of user data (for example Sales context) can use some kind of data replication architecture to sync user data as read only, for internal complex queries, or just decoupling from Cognito.
One example of data replication in this case could be listening to Cognito events (AWS Lambda can help with that) to replicate user data to a Bounded Context (just the part of the data you need for that context).
But remember that the replicated data is read only, the original Cognito data should be the single source of truth.
You can use AWS AppSync Lambda resolvers coupled with Cognito User Pools as the AuthZ choice for an AppSync API to satisfy your use case. Essentially when the user completes auth with cognito you will have the '$context.identity.claims' which contains the user attributes, and inside your lambda resolver you can write to your RDS DB.
Some reference docs:
Lambda Resolvers: https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html
AppSync Auth with User Pools: https://docs.aws.amazon.com/appsync/latest/devguide/security-authorization-use-cases.html

Best practice to store users "plan" and control their permission in AWS Cognito

Assume I have a web app application and I use aws cognito users-pool to manage my users. Also assume some of the users are just "Guests", some are in a "Regular" paid plan and some are under "Premium" paid plan.
Where is the best place to store the users plan information? Is it better to store it as a Cognito user attribute or in some key:value DB (e.g Dynamodb)?
How should I control what a user can do according to his plan? Should i check the user ID against his "plan type" value in Cognito user pool/DB for each http request he makes to the server? Is there a cheaper (resource wise) way to accomplish this?
Thanks
If your application is single tenant and you are using the particular Userpool only for this application, you can store the 'plan' in an custom attribute.
This would be difficult to manage if you use the same user pool for multiple applications or having multi-tenancy with different 'plans' for a single user.
To store the plan you can use either Dynamodb or Cognito Sync Storage.

Can you migrate AWS Cognito users between user pools?

I am using AWS Cognito. I have a pretty common scenario: users can register in different roles. Depending on the role different user attributes are required, so I need to use different user pools.
Now a user wants to upgrade from role A to role B - thus I would have to move his account from one pool to another. Is this possible with AWS? The response in Can you export/migrate users out of AWS cognito, does it cause vendor lock-in? seems to indicate the opposite.
If not possible this way, what would be a viable solution to achieve requiring different user attributes depending on different user roles with AWS Cognito. (NOTE: requiring / verifying them only on the front end is not a viable solution)
I know this question is a bit dated, but it is possible that this scenario is best solved by using Groups instead of a separate user pool for each role. See here
If you reach this link to find out how to transfer users to a new pool (for instance, you needed to create a new user pool in order to change how your users log in), then there isn't a built in way to do this. However, there are solutions that you could build in order to migrate users, which is referenced here:
Create your new user pool.
Modify your client to do the following:
On failed sign in with new user pool, attempt sign in with old user pool.
If existing user pool sign in is successful, use the username and password that was submitted to the existing sign in to create a user on the new user pool.
Possibly do something to remove the user from the old user pool or mark as migrated.
You can export users and import them to a new user pool with a CSV file, but your users will have to change their password.