We have a dynamo table that we use for a security-sensitive part of our application with pretty strict read-access restrictions (aiming for as strict as possible here). Ideally we would like to restrict access to that table to just the rows that have matching cognito-userId leading keys (following this approach: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_rows.html). Unfortunately, our requirements are such that a lambda function would need to read the values on behalf of the user in order to subsequently process and send the value to the user (for example via mail).
Our current set-up looks as follows: We've created the IAM rule with that leading-key IAM condition and attached it to a user-group which includes all users that will be accessing that table. So far so good, the lambda function fetches the rule from the context object and assumes that role (via sts:assumeRole, like so, they're both in the same account though: https://aws.amazon.com/premiumsupport/knowledge-center/cognito-user-pool-group/, https://aws.amazon.com/premiumsupport/knowledge-center/lambda-function-assume-iam-role/) Both the lambda as well as the assumed role have the necessary policies, so this, too, works as expected. Tests with static values, like the following:
ForAllValues:StringEquals:
dynamodb:LeadingKeys:
- "SOMEKEY"
also confirm that all required credentials are being passed, the role is being assumed, everything works until here.
Unfortunately, it stops working when actually using ${cognito-identity.amazonaws.com:sub}
as the leading key identifier, both with and without the aws-region prefix. Hence my question, has anyone encountered this before? When is this variable being substituted for the IAM rule? is it being resolved before it's being passed to the lambda function (in which case we would expect that value to be populated) or is it being substituted while lambda accessed dynamo (in which case it's not being resolved since lambda and not the cognito-user assumes the role)?
Are there ways to mitigate this? Any help would be greatly appreciated
${cognito-identity.amazonaws.com:sub} is referencing the Cognito's Identity ID, from the identity pool. Therefore, when your application uses the Identity Pool to obtain AWS temporary credentials, these credentials will contain the users Identity ID. If your application then tries to get a row from a database, the user can only get their row, the row with their identity ID as the leading key.
So instead of assuming the IAM role in the lambda function, using sts assume role, you could pass the Cognito ID token to your Lambda and then pass the ID token to the identity pool to obtain credentials. These credentials can then be assumed by the SDK and requests made to Dynamo will have use the ${cognito-identity.amazonaws.com:sub}.
One thing to mention about this approach, the credentials obtained from Identity Pool are valid for an hour so I believe implementing a caching layer to reuse existing credentials will be necessary to avoid requesting new credentials from the Identity Pool on every invocation.
Hope that helps.