Restricted Permission with Federated Identity

July 2, 2024

Overview

If you are familiar with a full-stack apps framework that performs temporary credentials like AWS Amplify, Baseline, or Appycloud, I would like to share how to restrict and optimize your data permission with Cognito Identity Pool. This post will focus on the data in DynamoDB and S3. I don’t have any experience with other data services that support this approach.

Let me start with a common IAM Policy to grant access to a Dynamodb Table and S3 Bucket:

It will give the associated Role access to send the request to any items/objects in a particular DynamoDB table/S3 bucket. But hold a second, now let’s compare this to the one below:

So, in particular use cases, sometimes we need to restrict the items/objects belonging to their role identity. Can I call it fine-grained accessibility from now on? CMIIW!

Well, what is fine-grained accessibility and how does it work? Let me provide a diagram to help you understand the basic flow:

The above diagram describes how each user has restricted access to its own Cognito identity ID as the key property. When the requests come from unmatched identity keys, they will be blocked. For example, if User 1 is trying to access any Dynamodb items where the PK matches to Identity 1, it succeeds. Another example, if User 2 wants to query the list of objects inside a folder whose name matches Identity 2, it will work as well. Otherwise, they will be introduced as “unauthorized access”.

Implementation

What are the requirements?

  • AWS Account
  • AWS Dynamodb
  • AWS Cognito Identity
  • AWS IAM Role Policy

Create a Dynamodb table, for example, named “demo-dynamodb-table” with a table schema that includes both a partition key and a sort key.

Next, create a new Cognito Identity to manage the user identities. For now, let’s keep it simple by setting up the unauthenticated role (guest access), and identifying the pool name, for example, "demopoolidentity."

Once the Identity Pool is created, we will adjust the IAM Role Policy document to implement restricted conditions. Go to IAM console, open the “demo-unauth-identity-role,” and edit the Permissions policies to be:

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

Now we are ready to validate the above configuration, here we go:

  • Get the identity:
  
aws --profile <AWS_PROFILE> --region <REGION> cognito-identity get-id --identity-pool-id <IDENTITY_POOL_ID>
  
  • Pass the unique Identity ID from the output in the get-credentials-for-identity API call to obtain temporary AWS credentials:
  
aws --profile <AWS_PROFILE> --region <REGION> cognito-identity get-credentials-for-identity --identity-id <IDENTITY_ID>
  
  • Set environment variables for the CLI with the obtained temporary security credentials:
  
export AWS_ACCESS_KEY_ID="<ACCESS_KEY>"
export AWS_SECRET_ACCESS_KEY="<SECRET_KEY>"
export AWS_SESSION_TOKEN="<SESSION_TOKEN>"
  
  • Test by making DynamoDB calls for that user identity ID:
  
aws --region <REGION> dynamodb put-item --table-name demo-dynamodb-table --item '{"PK": {"S": "<IDENTITY_ID>"}, "SK": {"S": "test 1"}}'
  
  • Test unauthorized calls with another user identity ID or random value for the PK attribute. It will throw an error message:

    An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:sts::xxxxx:assumed-role/demo-unauth-identity-role/CognitoIdentityCredentials is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:xxxx:xxxxxxx:table/demo-dynamodb-table because no identity-based policy allows the dynamodb:PutItem action
  
aws --region <REGION> dynamodb put-item --table-name demo-dynamodb-table --item '{"PK": {"S": "unauthorized_string"}, "SK": {"S": "test 2"}}'
  

The above sample is very basic, we can manage the condition based on the Identity Pool ID instead, for example, to allow one admin user access to all items. We can also manage the condition based on Authenticated roles, Defined attributes, etc. Please find out more best practices from the provided links on the last page.

Conclusion

When we use a full stack apps framework, most of them are set with common permissions. I am not saying it’s bad. I would prefer to say, there is an elegant way to improve the initial policy to make our apps more secure. I don’t need to write bulk codes to have a restriction flow for resources like Dynamodb or S3. They are managed very well through IAM Policy conditions.

Another thing I have to disclaim: this approach is for learning purposes, and references AWS official documentation. Please note there is a dedicated AWS Solutions Architect team that addresses the architecture and design-level queries for custom solutions.

References

https://repost.aws/questions/QUutSZgcSPQJiCL5p-ln_aVA/access-the-s3-folder-specific-to-particular-user-authenticated-using-cognito

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_items.html

https://aws.amazon.com/blogs/mobile/building-fine-grained-authorization-using-amazon-cognito-user-pools-groups/

https://docs.aws.amazon.com/cognito/latest/developerguide/iam-roles.html

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_s3_cognito-bucket.html

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html#FGAC_DDB.ConditionKeys

Serverless Handbook
Access free book

The dream team

At Serverless Guru, we're a collective of proactive solution finders. We prioritize genuineness, forward-thinking vision, and above all, we commit to diligently serving our members each and every day.

See open positions

Looking for skilled architects & developers?

Join businesses around the globe that trust our services. Let's start your serverless journey. Get in touch today!
Ryan Jones - Founder
Ryan Jones
Founder
Speak to a Guru
arrow
Edu Marcos - CTO
Edu Marcos
Chief Technology Officer
Speak to a Guru
arrow
Mason Toberny
Mason Toberny
Head of Enterprise Accounts
Speak to a Guru
arrow

Join the Community

Gather, share, and learn about AWS and serverless with enthusiasts worldwide in our open and free community.