aws-cdk: Cognito circular reference when setting lambda trigger permissions

Create a lambda Create a user pool Assign the lambda to one of the user pool triggers Set the permissions on the lambda to call Cognito APIs against the user pool Get circular reference error in cdk deploy

Reproduction Steps

    const postAuthentication = new lambda.Function(this, "postAuthentication", {
      description: "Cognito Post Authentication Function",
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: "postAuthentication.handler",
      code: lambda.Code.asset("dist/postAuthentication"),
      timeout: cdk.Duration.seconds(30),
      memorySize: 256,
      environment: {},
    });

    const userPool = new cognito.UserPool(this, userPoolName, {
     ....
      lambdaTriggers: {
        postAuthentication,
      },
    });

    const postAuthPermissionPolicy = new iam.PolicyStatement({
      actions: ["cognito-idp:AdminDeleteUserAttributes", "cognito-idp:AdminAddUserToGroup"],
      resources: [userPool.userPoolArn],
    });
   // now give the postAuthentication lambda permission to change things
    postAuthentication.addToRolePolicy(postAuthPermissionPolicy);

Error Log

Cognito failed: Error [ValidationError]: Circular dependency between resources

Environment

  • CLI Version : 1.31.0
  • Framework Version:
  • OS :
  • Language : Typescript

Other


This is 🐛 Bug Report

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 29
  • Comments: 30 (7 by maintainers)

Commits related to this issue

Most upvoted comments

@markcarroll -

The workaround for this issue is to not use the addToRolePolicy() but instead to attachInlinePolicy(). See code snippet below -

import { UserPool } from '@aws-cdk/aws-cognito';
import { Function, Code, Runtime } from '@aws-cdk/aws-lambda';
import { Policy, PolicyStatement } from '@aws-cdk/aws-iam';
import { App, Stack } from '@aws-cdk/core';

const app = new App();
const stack = new Stack(app, 'mystack');

const fn = new Function(stack, 'fn', {
  code: Code.fromInline('foo'),
  runtime: Runtime.NODEJS_12_X,
  handler: 'index.handler',
});

const userpool = new UserPool(stack, 'pool', {
  lambdaTriggers: {
    userMigration: fn
  }
});

fn.role!.attachInlinePolicy(new Policy(stack, 'userpool-policy', {
  statements: [ new PolicyStatement({
    actions: ['cognito-idp:DescribeUserPool'],
    resources: [userpool.userPoolArn],
  }) ]
}));

Can you check if this fixes this issue for you?

I have the same issue with providing the lambda function with the list of app clientIds as environment variables upon creation.

Has this been looked into ?

Today I noticed that userPoolId is inside event object for lambda.

Leave this open. I’d like to get a better solution for this in place. It’s more complicated than I originally thought it would be.

The grant* functions do not solve this problem. However, I’ve classified this as a bug.

I am facing a similar problem because I’m trying to pass the userPoolId in the Lambda trigger. Is there a way to know the userPoolId without passing it as an env var?

        const postConfirmationLambda = new lambdaNodejs.NodejsFunction(this, 'postConfirmationLambda', {
            entry: 'lambda-functions/user-pool-trigger/post-confirmation.ts',
            environment: {
                "USER_POOL": cognitoUserPool.userPoolId, /* This causes a circular dependency while deploying */
            }
        });

I’m facing a similar issue, I’m creating the lambdas after the UserPool and AppClients are created, I then use the app clients to populate a few env variables for the lambdas when creating them (I need a mapping so the event client id is not useful here), and then I just add them as triggers, so the issue is around the env variables, if I dont use the clients to populate it it works, otherwise just throws a circular reference

For me even attachInlinePolicy creates an error Do we know when the bug will be fixed?

I think trigger needs to be a new element like: new CognitoTrigger so the dependson can be added

this approach is the only way we have been able to solve for this currently

any further news on this? i’m havinga similar issue where a userpool depends on a lambda as it trigger for CustomMessage but the lambda needs the userpoolid as an environment variable

Lambda receives userPoolId in the event argument.