currently I am working with AWS DynamoDB and I struggle with user authorization and restricting access to specific items inside of a DynamoDB Table. I have already read the documentation and came across multiple blog posts, but unfortunately I haven't found my use case yet.
Some background information:
Each user of the web app belongs to a company and each company has multiple orders. These orders are inside of the DynamoDB table "Orders". What I want to achieve is that the users can only read order items from the company they belong to.
My Approach
My idea was to create the "Orders" table with a partition key of "companyId" and a sort key of "orderId". During my research I figured out that I can restrict the access through IAM Policy roles, but I couldn't find a way to access the companyId of the user inside of the policy role. Users are authenticating through AWS Cognito.
My Question
How can I restrict the user access specific items inside of a DynamoDB? Taking into account the each user belongs to a company and should only see orders of this company.
Looking forward to some help!
CodePudding user response:
Using custom attributes, you can create a backend layer that will check these parameters, query DynamoDB with the specified attribute, and return them - https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-attributes.html
The second option is to set up role for each company - https://docs.aws.amazon.com/cognito/latest/developerguide/role-based-access-control.html#using-rules-to-assign-roles-to-users
CodePudding user response:
AWS has published Isolating SaaS Tenants with Dynamically Generated IAM Policies blog on their website. This blog explains exactly the thing that you want to achieve.
In short, I can explain:
Use CustomerId as PartitionKey
Create an IAM policy with access on Orders table like below
1 { 2 "Version": "2012-10-17", 3 "Statement": [ 4 { 5 "Action": [ 6 "dynamodb:GetItem", 7 "dynamodb:BatchGetItem", 8 "dynamodb:Query", 9 "dynamodb:DescribeTable" 10 ], 11 "Resource": "arn:aws:dynamodb:us-west-2:123456789012:table/Orders", 12 "Effect": "Allow" 13 } 14 ] 15 }
Create a template for Session Policy where you will replace CustomerId with incoming request's customerId on runtime.
1 { 2 "Effect": "Allow", 3 "Action": [ 4 "dynamodb:*" 5 ], 6 "Resource": [ 7 "arn:aws:dynamodb:*:*:table/{{table}}" 8 ], 9 "Condition": { 10 "ForAllValues:StringEquals": { 11 "dynamodb: LeadingKeys": [ "{{customerId}}" ] 12 } 13 } 14 }
Now, invoke STS (Security Token Service) with above IAM & Session policy to get temporary credentials that has access limited to a single tenant/customer data.
Below is the pseudo code, you can use your programming language's SDK to write below code.
AssumeRoleResponse response = sts.assumeRole (ar -> ar .webIdentityToken(openIdToken) .policy(scopedPolicy) .roleArn(role)); Credentials tenantCredentials = response.credentials(); DynamoDbClient dynamoDbClient = DynamoDbClient.builder() .credentialsProvider(tenantCredentials) .build();
Finally, create
DynamoDBClient
object using these temporary credentials and use it. This object ofDynamoDBClient
will have access to only current user's customer data.
Hope this should help!