I am trying to implement a public file sharing system for my application using AWS Cognito & DynamoDB. Basically users can create and sign into an account using Cognito and use this account to upload their files. Public meta data that needs to be accessed frequently goes to DynamoDB (such as ratings, download count, upload date, etc.) and the files itself to an S3 bucket.
To ensure that only the Cognito user who shared the file is allowed to delete the DynamoDB item and modify certain private attributes, I am using the Cognito identity id as the primary key for my items inside the DynamoDB, coupled with a policy rule as described in the docs. Afaik there is no other solution.
So far so good, but this obviously means that a user cannot upload more than 1 item to the database since the primary key attributes of DynamoDB items need to be unique, which is not possible since I am using the Cognito identity id for them.
I could of course create one item for each user and store the meta data for each file he owns inside maps, but this wouldn't allow me to query the items by date, rating, etc.
I'm honestly stuck and cannot think of a way to structure my database items any other way to make this work. Is this even feasible with DynamoDB?
You can create a range key with a unique id for each file, while maintaining the primary key as Cognito id which allows to keep the DynamoDB fine-grained authorization.
Related
I am creating an application. The users can register and log in via AWS Cognito and MFA SMS Verification.
The specific user information, created in the app, will be stored in a DynamoDB table.
My idea is to use the UserID from Cognito as the Partition Key (user_ID) in DynamoDB.
My first thought is to use a Lambda function that is triggered when a user successfully registered in my app, and creates a User item in DynamoDB with the Cognito UserID as Partition Key (user_ID).
Does this make sense or is there a best practice how to set this up?
Yes this makes sense and is what most people use for Cognito as it allows you to use DynamoDB's fine grained access control, meaning users logging in can only access information belonging to them in your DynamoDB table, offering an extra layer of security.
I read some questions and answers about my issue, but I still don't know the answer.
Can I use the userSub in AWS Cognito as primary key?
AWS Cognito: Difference between Cognito ID and sub, what should I use as primary key?
First, I will try to describe my case.
I want to create an application with spring boot as a resource server that uses oauth2. Then to save me some time with user management, I was hoping to use AWS Cognito since it allows me to create users as admin. I can set it up that it won't let other people sign up for themselves, which is crucial for me since my app will have restricted access; the admin will manage that.
Now to my question, which field of AWS Cognito can I use as the primary key for keeping user-specific data in my DB? I read that neither usernamenor sub is correct.
username can be changed, for example, and sub is globally unique, so it can't be restored. Is there any way to create a custom field where AWS Cognito will autogenerate UUID that I can use, and if I had to restore the user pool, I would have an option to set this field?
You can still go with username. If it is ever changed, just update your database to reflect this change.
You can also create a custom attributes in user pool. You can use that to store a self generated id. As for automatically generating this, you can have a post confirmation lambda trigger that will use adminUpdateUserAttributes to assign a unique id.
I want to build an AWS architecture for a serverless application which stores files in a DynamoDB.
This database stores data which relates to a given perimeter. On the other hand I have data (M:N links) which link users of my application to some perimeters.
I want to make sure that my users (Authenticated on Amazon Cognito via a federated OIDC provider) only access to the data related to one of their perimeters.
What is the best practice to implement this kind of access control logic with Amazon bricks ?
Is it possible to accomplish such access control logic with IAM policies at the Dynamo DB level ?
You can add a table
UserPerimeter
---
id (hash key)
userId (index - hash key)
perimeterId
And as part of your validation in your Lambda, you do a query on the index with the the user id from JWT/Cognito. This will check if he has access to the requested parameter. So basically protect your DB from your code (which is the only point of access).
You can achieve this from IAM, (check this article) but it adds too much complexity for my taste. This would be useful if the DB is used by multiple products/components/companies (which isn't a good practise anyway).
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
Is there any way of controlling access to DynamoDB data based on data in other tables? By way of comparison, Firebase Realtime Database rules have access to a snapshot of the entire database when being evaluated, so rules like this are possible:
".write": "root.child('allow_writes').val() === true"
But all my reading of the AWS permissions structure hasn't given me any clue how to achieve the same thing. There are variables that can be tested based on the current authenticated user, and some variables based on the current request, but no way I can see of referencing other data within the database.
AWS don't support this case, you're only option would be to put the access control in your application.
You can control table, item or attribute level data access in DynamoDB using a IAM policy variables. Frustratingly AWS don't even seem to publish a list of available policy variables. Typically it boils down to using Cognito sub or AWS userid, which the majority of people don't want to use as a partition keys in their tables.