Search code examples
typescriptamazon-web-servicesaws-lambdaamazon-iamaws-cdk

AWS IAM assumeRole with session tag permission issues


I do have a aws-cdk application where I do want a lambda function to assume a certain role and get credentials vis aws-sts. The credentials shall contain a tenant_id tag.

AWS CDK Code:

Role to be assumed:

const pdfUserRole = new Role(this, "PDFTenantUserRole", {
  assumedBy: new ServicePrincipal("lambda.amazonaws.com").withSessionTags(),
  description: "Role assumed by the pdf service for a user",
});

// https://docs.aws.amazon.com/IAM/latest/UserGuide/id_session-tags.html
pdfUserRole.addToPolicy(
  new PolicyStatement({
    actions: ["sts:TagSession"],
    resources: ["*"],
  })
);

Lambda Function definition:

this.pdfGeneratorFunction = new LambdaFunctionTypescript(
  this,
  "Handler",
  {
    tracing: Tracing.PASS_THROUGH,
    entry: getFilePath(import.meta.url, "pdf-generator-function.ts"),
    memorySize: 1536,
    layers: [],
    initialPolicy: [
      new PolicyStatement({
        resources: [pdfUserRole.roleArn],
        actions: ["sts:AssumeRole", "sts:TagSession"],
      }),
    ],
  }
);

This role shall be assued by the lambda function like so (handler code)

const sts = new STSClient({});

const getCredentials = async (tenantId: string) => {
  return sts.send(
    new AssumeRoleCommand({
      RoleArn: userRoleArn,
      RoleSessionName: "PDFGenerator_" + tenantId,
      TransitiveTagKeys: ["tenant_id"],
      Tags: [
        {
          Key: "tenant_id",
          Value: tenantId,
        },
      ],
    })
  );
};

The lambda function gets associated with a service role which contains the inline definition from the handler.

I am unable to run the code since the function will error saying my lambda function cannot call the AssumeRole:

User: arn:aws:sts::<AWSAccountId>:assumed-role/PDFGeneratorHandlerServiceRole/PDFGeneratorHandler is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::<AWSAccountId>:role/PDFGeneratorPDFTenantUserRole

I do suspect a principal issue since it looks like it is not calling as lambda but more like the service role, but I already tried to add a trust relationship between the function and the role that did not work either.

Update: The credentials the lambda functions creates are the be used within a virtual browser, so its not for the lambda function itself.

Update 2: Here is a link to an example: https://github.com/aws-samples/multi-tenant-database-isolation-patterns/blob/2000b9ff4630d181421a8761ffea3f7a9039eacf/patterns/3-pool-compute-db-per-tenant-iam-auth/silo-compute-iam.ts#29


Solution

  • You are mixing two concepts here: the IAM role of the lambda function and what your code within your lambda function does.

    The role for the first one needs the trust relationship to allow lambda to assume it. And the lambda service will automatically fetch those credentials before running your code, your function cannot work without such a role and proper trust relationship.

    The second part is what your code. When your code then attempts to e.g. assume any other role it uses the credentials it already got from the lambda service. In particular this means that any further actions with those credentials are no longer related to the service principal for the lambda service itself.


    Your role only allows the lambda service to assume it, which is why the assume call from within your function fails. Your function already has valid credentials for the role and there is not need to actually perform the assume role call manually. If for some reason you do actually need further role assumes then those roles need to trust the actual role your lambda runs with, NOT the lambda service itself.

    Adding a trust relationship on the role to be assumed by the lambda function`s service role could look like this:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::<AWSAccountId>:role/PDFGeneratorHandlerServiceRole"
                },
                "Action": [
                    "sts:AssumeRole",
                    "sts:TagSession"
                ]
            }
        ]
    }