4

My AWS Lambda function is trying to write to dynamodb. Users who log in from client app call the AWS API-Gateway endpoint that further calls the AWS Lambda function. These Users are created in AWS Cognito User pool. Login is done using Identity Pool (Federated Identity). Which means, first login using username and password gives Id_token which is exchanged with temporary IAM credentials and session token. User is in a group that has associated a role that allows writing to dynamodb table.

AWS Lambda function looks like this -

def create_profile(event, context):
    profile = json.loads(event["body"])

    session = boto3.Session(region_name='eu-west-2')
    ddb_client = session.client('dynamodb')
    row_id = str(uuid.uuid4())
    item = {
        'RowID': {
            'S': row_id
        },
        'first_name': {
            'S': profile['first_name']
        },
        'last_name': {
            'S': profile['last_name']
        }
    }

    ddb_client.put_item(TableName='Persons', Item=item)

(This is just a test code. so no validations etc. and please ignore that part)

I get this error

[ERROR] ClientError: An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:sts::<ACCOUNT_ID>:assumed-role/<PREFIX>-CreateProfileFunctionRole-1VOW05TI1WR20/<PREFIX>-CreateProfileFunction-gqmkkzOP1Ro7 **is not authorized to perform:** dynamodb:PutItem on resource: arn:aws:dynamodb:eu-west-2:<ACCOUNT_ID>:table/Persons **because no identity-based policy allows** the dynamodb:PutItem action
    Traceback (most recent call last):
      File "/var/task/app.py", line 23, in create_profile
        ddb_client.put_item(TableName='Persons', Item=item)
      File "/var/runtime/botocore/client.py", line 391, in _api_call
        return self._make_api_call(operation_name, kwargs)
      File "/var/runtime/botocore/client.py", line 719, in _make_api_call
        raise error_class(parsed_response, operation_name)

My question is, why does it say "because no identity-based policy allows" since I have added AdministratorAccess managed policy already. I am thinking that the python code written above is not running under the federated identity to do further operations on more services.

I have checked that the role that the Cognito Group is associated with is "assumed" since the role can be seen in Id_token when seen in jwt.io.

Is there something wrong with my python code? Do I need to do something explicit to run it under the assumed identity to do further calls to more aws services?

Sandeep
  • 335
  • 1
  • 2
  • 24
  • check if DynamoDB `table/*` is allowed. Object-level vs Directory level access. [AWS docs](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_lambda-access-dynamodb.html) – niko Jun 08 '22 at 15:46
  • user has AdministratorAccess – Sandeep Jun 08 '22 at 16:10
  • its depends on [policy evaluation logic](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html) – niko Jun 08 '22 at 16:13
  • There is no explicit deny. AdminstratorAccess would then provide most liberal of all "Allow"s – Sandeep Jun 08 '22 at 16:22
  • 2
    Your user Identity is allowing the API to be invoked, Lambda is invoked by the API Gateway service and the Lambda itself is run under the role assigned the Lambda function. Just have to make sure that role has putItem access. – JoeW Jun 08 '22 at 16:37
  • Thanks @JoeW. That was the problem! – Sandeep Jun 08 '22 at 17:18
  • Hi @JoeW, however now the lambda function can write to dynamodb table even if the federated user doesn't have access to the table. So the permissions of end user are checked only at the api level. which means, there's not much granularity of permissions. Is this how it is supposed to be? – Sandeep Jun 08 '22 at 17:28
  • @Sandeep fine-grained access is possible. You can create the ddb client with web identity credentials if you want database permission to be scoped based on a user's ID token. See documentation here: https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html – Ross Williams Jun 09 '22 at 08:27
  • Hi @Sandeep, glad you were able to get past the initial issue. To answer your question about providing granularity, there a few options. I think you may wan to investigate [this blog](https://aws.amazon.com/blogs/security/building-fine-grained-authorization-using-amazon-cognito-api-gateway-and-iam/) which explains a way of doing this. Basically need a custom authorizer function to pass down something like groups which can be cheked by your main Lambda to ensure the user has acceess. – JoeW Jun 09 '22 at 08:33
  • Thanks @RossWilliams. Will check that out too. Appreciated your help! – Sandeep Jun 09 '22 at 11:47
  • I highly recommend you do not use AdministratorAccess for any of this if you can help it. Make sure you have a policy just for the DynamoDB access https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/using-identity-based-policies.html – NoSQLKnowHow Jun 10 '22 at 00:02
  • I don't intend to. It was just a test as I had mentioned in the question itself. – Sandeep Jun 10 '22 at 00:28

1 Answers1

3

I faced a similar issue. I managed to fix this by adding the explicit policy to that the role <PREFIX>-CreateProfileFunctionRole-1VOW05TI1WR20

On the role add the following policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "dynamodb:PutItem",
            "Resource": "arn:aws:dynamodb:eu-west-2:<ACCOUNT_ID>:table/Persons*"
        }
    ]
}

For me the problem was resolved. Hope it helps for you.

Rik
  • 3,647
  • 2
  • 25
  • 34