Cognito Fine Grained to dynamodb

1

I haven't found a good concise answer to this most basic usecase. Lots of content, but nothing that works, or fundamentally addresses or explains the issue.

I have a cognito userpool and identity pool. I can login and get a sub (from the userpool) and an identityid (from the identitypool). I want to putItem to a dynamodb table based on one of those. I'd rather use the sub because I can directly look that up from the userpool. The identityis is a confusing level of indirection if I ever need to edit the table directly (and also easily deleted). But, I get that its better to use the identityid because that can be tied to multiple logins.

I can putItem with full table putitem permissions in the policy. I want to limit puts to just this user through fine grained access. in other words I don't want this user putting records to some other users' ID... I could just leave the puts open to all users, which is sort of the end effect, I just want to ensure the specific user can "only" write their userid to the table. The problem is this confusing mapping to leadingkeys. None of the field names make sense in the mapping, so I have no idea what to use.

Ultimately I also want to limit getItems and queries to just that user too.

This seems like what I should be using in the policy, but it doesn't work with either the sub or the identityid. Its also not clear how this maps to the table or indexes. I have a userId index field in the table, but have no idea how this is supposed to map to that. Can you define what "LeadingKeys" means? Is it an index on the table, or on the IAM (from the identitypool)? Is this supposed to be set on the user's permission, or do I need to specify this on the table permissions itself? "Condition": { "ForAllValues:StringEquals": { "dynamodb:LeadingKeys": [ "${www.amazon.com:user_id}" ] } }

2 Answers
0

I have been digging for a while about this too.

There were 2 prerequisites that I hadn't fulfilled which were:

  • Enabling default mappings in the identity provider of the identity pool. This maps the Tag key of 'username' to 'sub'
  • The trust relationship of the role you are assuming must have the action 'sts:TagSession'. I believe this allows the attributes we are checking to be passed through. I still have more to understand about this part and why it is essential.

This left my policy with a statement like:

        {
            "Action": [
                "dynamodb:UpdateItem",
                "dynamodb:Query",
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:DeleteItem"
            ],
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:LeadingKeys": "${aws:PrincipalTag/username}"
                }
            },
            "Effect": "Allow",
            "Resource": "*"
        }

With my trust policy like:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "cognito-identity.amazonaws.com"
            },
            "Action": ['sts:AssumeRoleWithWebIdentity', 'sts:TagSession'],
            "Condition": {
                "StringEquals": {
                    "cognito-identity.amazonaws.com:aud": "us-east-1:my-identity-pool"
                },
                "ForAnyValue:StringLike": {
                    "cognito-identity.amazonaws.com:amr": "authenticated"
                }
            }
        }
    ]
}

If you are using CDKTF like I am, you need to create a CognitoIdentityPoolProviderPrincipalTag, which is where attribute mapping can be done. In console, got to your Identity Pool -> User Access -> Identity Providers and ensure you have the default mappings enabled. This lets you use the aws:PrincipalTag/username to match on the users sub

Hopefully this helps! Good luck.

https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html https://stackoverflow.com/questions/56801845/iam-policy-cognito-variables-for-dynamodb-leadingkeys-restriction

answered 25 days ago
-1

To implement fine-grained access control for DynamoDB using Amazon Cognito, you need to understand a few key concepts:

  1. LeadingKeys: This refers to the partition key of your DynamoDB table. It's called "leading" because it's the primary key that DynamoDB uses to partition data.

  2. Cognito Identity ID vs. User Pool sub: While you can use either, the Cognito Identity ID is generally preferred for fine-grained access control because it can handle both authenticated and unauthenticated users.

To set up fine-grained access:

  1. Structure your DynamoDB table: Ensure your table uses the Cognito Identity ID as the partition key.

  2. Set up IAM policy: Create a policy that allows actions on the DynamoDB table, but only when the LeadingKeys match the user's Cognito Identity ID.

Here's an example policy:

{
   "Version": "2012-10-17",
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "dynamodb:GetItem",
            "dynamodb:PutItem",
            "dynamodb:UpdateItem",
            "dynamodb:DeleteItem",
            "dynamodb:Query"
         ],
         "Resource": "arn:aws:dynamodb:REGION:ACCOUNT_ID:table/TABLE_NAME",
         "Condition": {
            "ForAllValues:StringEquals": {
               "dynamodb:LeadingKeys": [
                  "${cognito-identity.amazonaws.com:sub}"
               ]
            }
         }
      }
   ]
}

This policy allows the specified DynamoDB actions, but only on items where the partition key matches the user's Cognito Identity ID.

  1. Attach the policy: Attach this policy to the IAM role associated with your Cognito Identity Pool.

When using this setup:

  • Each user can only access their own data in the table.
  • The condition ensures that a user can't write data with someone else's ID as the partition key.
  • Queries and GetItem operations will only return results for the user's own data.

Remember, this approach requires your application to use the Cognito Identity ID as the partition key when writing to DynamoDB. Your application will need to retrieve this ID after user authentication and use it in DynamoDB operations.

This setup provides a secure way to implement per-user data isolation in DynamoDB using Cognito, addressing your need for fine-grained access control.
Sources
IAM roles - Amazon Cognito
Amazon DynamoDB: Allows item-level access to DynamoDB based on an Amazon Cognito ID - AWS Identity and Access Management
Enable fine-grained access control and observability for API operations in Amazon DynamoDB | AWS Database Blog
Using IAM policy conditions for fine-grained access control - Amazon DynamoDB

answered a month ago
  • Ok, so leadingkeys (plural) means only one key and that's the partitionkey (which makes sense in hindsight, but not at all clear in the documentation... I was expecting to be able to use an index... i.e. any of the keys, but that's not the case). It also doesn't seem to have to be named anything specific except for the fact that its the partitionkey.

    Now if I have a complex partitionkey like [RECORDID][USERID][someotherthing], can I map the leadingkeys into that, or does the partitionkey have to be exactly and only whatever the leadingkeys field points to?

    For Queries, do I have to explicitly specify the userid (leadingkeys/primarykey)? That's more of a performance question.

    Also, did AI just produce an actual and helpful answer? I'm sold!

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions