I'm attempting to use AWS Cognito to aid support for multi tenancy within my application.
https://aws.amazon.com/blogs/apn/managing-saas-users-with-amazon-cognito/
Provisioning User Pools
Assuming you were to associate a single user pool with each tenant,
you would need to introduce provisioning automation that would create
a tenant’s user pool during the sign-up process. This would also
require automation that configures all the other moving parts of
Amazon Cognito to declare and associate the user pools with the other
Amazon Cognito constructs and security policies.
The basic steps here would be to first create a user pool for the
tenant and apply any tenant-specific customizations or policies (these
would typically be the same for all tenants). Then, you’d need your
automation to provision and configure an identity pool. Finally, you’d
have to associate the identity pool with your newly created user pool.
The process is a bit more involved than that, but these are the key
concepts you need to have in mind as you think about how to add this
automation to your tenant creation lifecycle.
AWS provides a series of APIs that you can use to implement your
provisioning automation model. These APIs are available for a number
of different languages and environments.
So far I've been able to use the SDK to create many of the bits and pieces but am struggling with createIdentityPool () specifically CognitoIdentityProviders
The documentation states that CognitoIdentityProviders should contain...
ProviderName — (String) The provider name for an Amazon Cognito
Identity User Pool. For example,
cognito-idp.us-east-1.amazonaws.com/us-east-1_123456789.
ClientId — (String) The client ID for the Amazon Cognito Identity User
Pool.
ServerSideTokenCheck — (Boolean) TRUE if server-side token validation
is enabled for the identity provider’s token.
Where should I be getting ProviderName and ClientId from?
I have vars holding the values returned from createUserPool() and createUserPoolClient() but can't see anything within them that fits.
Any help appreciated.
ClientId is just the unique identifier for your client.
ProviderName is a constant string of the above format, just plug in region and user pool id where appropriate.
The easiest way to do this is via the Cognito federated identities console. It just takes in a user pool id and client id, which you get upon creating them in the Cognito user pools console.
If creating the identity pool from the SDK is a must, you can just get these values from the Cognito user pools console. Just look for the pool and client in question.
If using the console is out of the question, you can call ListUserPools and ListUserPoolClients to get the right ids.
I searched and couldn't find a definitive way to find or format the ProviderName.
I eventually figured it out from the CloudFormation example here.
ProviderName in the case of Cognito has this simple structure:
cognito-idp.{region}.amazonaws.com/{user_pool_id}
I've also found cases where it's necessary to also append the user pool client id like so:
:{user_pool_client_id}
Related
I have read about AWS cognito and I understand that User pools is an identity provider that is used to authenticate users to your mobile app, website and manage users. Then there is Identity pools that are used to authorize users to give access to your aws resources such as IAM, S3 and etc.
So my question is: Are identity pools used for the app management like by devs, dev-ops or anyone who needs to manage/update the apps? Is that the work of identity pools?
Identity pools are not (necessarily) used for app management. I can tell you about how my team used them at my last job. (There are probably other use cases, but I suspect ours was a fairly common one.)
We were building an app where users needed to upload and download files that we would store in S3. For various reasons, we wanted the client to interact directly with S3 for file transfer (as opposed to pushing files through an API layer that we would have to maintain). Identity Pools were made for exactly this sort of scenario. Basically they allow a client to exchange an identity token for a set of temporary IAM credentials (access_key_id + secret_access_key + session_token). The temporary IAM credentials are what the client needs to interact with an AWS SDK or create a signed HTTP request for one of AWS's native services.
The identity token that gets exchanged for credentials could be provided by Cognito User Pools, but it could also come from a different identity provider. We used Auth0 as an identity provider, for example. But we still wanted our client to interact directly with S3 and for that we needed Cognito Identity Pools.
One really cool feature of Identity Pools that we took advantage of was what Cognito calls Principal Tag Mapping, which is the ability to map claims (attributes) in the Auth0-provided identity token to session tags, which are kind of like environment variables that are attached to the temporary credentials' session. You can then write IAM policies that incorporate session tags to do attribute-based access control. We wrote S3 bucket policies that provided fine-grained access control where each user was only allowed to read and write to a prefix that contained their own user id.
I have to say that the distinction between User Pools and Identity Pools in Cognito confuses everyone and AWS's documentation isn't always as helpful as it could be on this point.
I am using AWS Cognito for user management. I want users of my application to store their data in DynamoDB. So I need user-scoped access (User A can write data and only read data added by User A, User B being able to only read data added by User B).
Docs suggest the ability to have row-level and column-level fine grain access: (https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html).
BUT I am not using IAM, I am using Congito users (want it scoped to each user, not a Role/Group). This doc suggests you can use Cognito ID: (https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_items.html).
However, according to this StackOverflow question (How to use DynamoDB fine grained access control with Cognito User Pools?), it's not what I am expecting?
Does AWS support my use-case? Lot of docs but its not clear if my use-case is supported.
You need to use Cognito identity pool. Cognito identity pool acts as an identity broker. When a Cognito user authenticates using the user pool, then Cognito provides JWT tokens. User can use ID token provided by Cognito user pool and Cognito identity pool can take the token and provide temporary IAM credentials.
I am familiar with a similar use case as of yours. In that use case, user who has written data to S3 can only modify/delete that data. In this case, you can create new S3 folders (prefixes) for each user's Identity ID (provided by Cognito identity pool) and that particular user can access data under that S3 folder only.
I am not much familiar with DynamoDB access control, hence not able provide the exact solution now. You can try a similar approach as the above one.
https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-create-identity-pool.html
I have an App client created for a Cognito User Pool. The client has an ID and secret generated. It is configured to use the Client credentials flow and has a custom scope defined. With that in place, I'm able to successfully exchange the creds for an Access Token, so far so good.
I would like to use AWS SDK to manage users (list, delete etc) in the User Pool with the server-side app client. Assuming I validated the granted token, how do I use it with AWS SDK to execute Actions I need? Is there a better way to manage User Pools from a server-side app?
If you look at Admin* level actions in the Cognito SDK (e.g. AdminDeleteUser), you will see it does not accept access tokens. It rather expects valid AWS developer credentials.
So what you probably want to do is to create an IAM role with appropriate permissions to manage the user pool (resource format: arn:aws:cognito-idp:REGION:ACCOUNT_ID:userpool/USER_POOL_ID) and let your server application assume that role. With correct permissions configured, you can call the AWS SDK directly.
You can find the list of available IAM actions here.
Is using an IdentityPool mandatory with AWS Cognito?
My use case:
My web app has users who can self-signup and will be added to the Cognito UserPool I have set up. I only want to provide access to my backend resources to authenticated users (ie., users belonging to an authenticatedRole IAM role). My requirement is simple enough that a single authenticated role suffices to handle my application's resource authorization requirements and I just want to deny access to all backend resources for non-authenticated users.
Is this possible with just the UserPool and if yes, how do I go about accomplishing this?
Note: I am using CDK to define my Infrastructure as code.
Using an identity pool is by no means mandatory with Cognito. It is completely on a use case basis. A few things to clarify here.
Userpool - For authentication
Identity Pool - For authorization.
Basically, if you want your end users to sign-up, sign-in, and then access AWS resources or make AWS API calls, then you would have to use an Identity pool. So let’s say you have a gaming application where the end user can sign in via FB, Google, or natively (username and password). This is authentication, and here we would be using a Cognito user pool. Now the user, is logged in and playing the game. They make a high score. This high score may need to be added to S3 or a DynamoDB table record for the user. For this, an identity pool is used. An identity pool will help you with vending temporary AWS credentials that the end user can use.
I believe in your use case the userpool should be sufficient. You can grant access to your resources by verifying the access token returned by Cognito for the end user.
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.