-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cognito circular reference when setting lambda trigger permissions #7016
Comments
Your user pool requires your Lambda function to be created first, but your function's policy depends on on your user pool's ARN, causing the circular dependency. Removing |
Providing the |
Sorry, that didn't work. I added const postAuthentication = new lambda.Function(this, "postAuthentication", {
description: "Cognito Post Authentication Function",
functionName: stackName + "-postAuthentication",
runtime: lambda.Runtime.NODEJS_12_X,
handler: "postAuthentication.handler",
code: lambda.Code.asset("dist/postAuthentication"),
timeout: cdk.Duration.seconds(30),
memorySize: 256,
environment: {},
}); Then after the user pool is defined I added: const postAuthPermissionPolicy = new iam.PolicyStatement({
actions: ["cognito-idp:AdminDeleteUserAttributes", "cognito-idp:AdminAddUserToGroup"],
});
postAuthPermissionPolicy.addResources(userPool.userPoolArn);
postAuthenticationLambda.addToRolePolicy(postAuthPermissionPolicy); As soon as I switched out In other CDK areas there are |
The |
… function role Lambda functions can be used as [triggers] on Cognito user pools. It is common for these triggers to query (callback) the user pool for more information. The function's IAM policy needs to updated with permissions to call the Cognito IDP service with the resource restricted to the specific user pool. Adding such an IAM policy creates a circular reference between the user pool, which refers to the lambda function, and the function policy, which refers to the user pool. This fixes the problem by using the `functionName` initialization property, when specified, to determine the `functionArn`, thereby, removing its dependency on the function being created first. fixes #7016 [triggers]: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html
The workaround for this issue is to not use the 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? |
This issue has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. |
Please ignore the message from the bot. I've removed the labels that triggered this. |
The attachInlinePolicy workaround seems to do the trick. Do you want to close this or keep it open? |
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. |
discussed this issue with @nija-at and @rix0rrr deployed this sample application inspired by the OP import { PolicyStatement } from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import { App, Stack } from '@aws-cdk/core';
import { UserPool } from '../lib';
const app = new App();
const stack = new Stack(app, 'integ-user-pool-client-explicit-props');
const fn = new lambda.Function(stack, 'fn', {
code: lambda.Code.fromInline('foo'),
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
});
const userpool = new UserPool(stack, 'pool', {
lambdaTriggers: {
postAuthentication: fn,
},
});
const postAuthPermissionPolicy = new PolicyStatement({
actions: ['cognito:DescribeUserPool'],
resources: [userpool.userPoolArn],
});
// now give the postAuthentication lambda permission to change things
fn.addToRolePolicy(postAuthPermissionPolicy); this produced a stack with a circular dependency -> the trigger Lambda function has a dependency on the role policy, which has a dependency on the user pool, which has a dependency on the lambda function. The problematic edge is the one between the function and the role policy - this should not be necessary as the role policy is already depending on the Lambda execution role (which the Lambda function also depends on). This problem will appear in any resource that has a Lambda function and a subsequent call to As mentioned earlier by @nija-at, the workaround is to use import { Policy, PolicyStatement } from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import { App, Stack } from '@aws-cdk/core';
import { UserPool } from '../lib';
const app = new App();
const stack = new Stack(app, 'integ-user-pool-client-explicit-props');
const fn = new lambda.Function(stack, 'fn', {
code: lambda.Code.fromInline('foo'),
runtime: lambda.Runtime.NODEJS_12_X,
handler: 'index.handler',
});
const userpool = new UserPool(stack, 'pool', {
lambdaTriggers: {
postAuthentication: fn,
},
});
fn.role?.attachInlinePolicy(new Policy(stack, 'userpool-policy', {
statements: [new PolicyStatement({
actions: ['cognito-idp:DescribeUserPool'],
resources: [userpool.userPoolArn],
})],
})); This issue is now being tracked under the |
For me even attachInlinePolicy creates an error I think trigger needs to be a new element like: new CognitoTrigger so the dependson can be added |
I want to mention that, I'm passing user pool id as the env variable and it has the same error effect. This just makes things weird, that I need to pass userPoolId in the parameter store to utilise it in the lambda. |
Today I noticed that userPoolId is inside event object for lambda. |
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. |
I had the same problem and i ended up doing something like this
Basically the trick is retrieve the role as if it was created in another stack. (i know and i don't like it as well) but it seems to do the trick for now. |
This saved me. I also got this error when trying to pass the pool.userPoolId to the lambda environment. But now I don't need to do that because it is included in the event, because it's a cognito post confirmation trigger. Thanks! |
I'm running into this exact circular dependency but from CloudFormation. How can I implement this delayed adding of the policy to the lambda role? |
@shawnmclean Not sure if you're still running into that issue, but normally with regular CloudFormation you'd use the If you have a resource that needs a policy based on the Role, but the Role also needs a policy specifying the resource, the chain will go: Each depends on the one prior, but since the Managed Policy is created at a later point and attached to the IAM Role, it is not circular. |
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 ? |
Problem still exist, but workaround with |
This issue has received a significant amount of attention so we are automatically upgrading its priority. A member of the community will see the re-prioritization and provide an update on the issue. |
I have two app clients, and want to do different things in cognito triggers based on the app client the user is coming in via... think mobile app client vs web. if event.callerContext.callerContext.cliendId = appClientId { do stuff } else if event.callerContext.callerContext.cliendId = webClientId { do different stuff. } I'm getting circular reference when creating cognito, added a second client, and then trying to bind the Ids of the clients into params and/or env vars. Is there a workaround for this? cognito depends on the trigger lambdas I really don't want to use ssm at trigger runtime to get the ids. |
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 */
}
}); |
Just to add to the discussion I resolved it using cloud trail events:
This way each time an operation is made through the Cognito API I route an event to this lambda. |
for me everything works smashingly until |
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 |
this approach is the only way we have been able to solve for this currently |
You can use event.userPoolId inside of the lamba |
this save me to avoid the error when passing variable environment to lambda |
I ran into this issue but regarding using a User Pool Id or User Pool Client Id as an environment variable for a Lambda function I was assigning as a trigger to the User Pool. const userPool = new cognito.UserPool(this, "UserPool", {
...
});
const client = new cognito.UserPoolClient(this, "UserPoolClient", {
userPool,
...
});
const lambdaFunctionName = "function-name";
const lambdaFunction = new lambda.Function(this, "LambdaFunction", {
functionName: lambdaFunctionName,
environment: {
USER_POOL_CLIENT_ID: client.userPoolClientId,
},
...
});
userPool.addTrigger(
cognito.UserPoolOperation.PRE_SIGN_UP,
lambda.Function.fromFunctionArn(
this,
`PreSignUpLambdaFunction`,
`arn:aws:lambda:${props.env.region}:${props.env.account}:function:${lambdaFunctionName}`
)
); |
This is still an issue in 2024. The |
I encountered a similar situation, and this approach was very helpful. In my case, when I used For reference, here are the errors I encountered:
|
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
Error Log
Cognito failed: Error [ValidationError]: Circular dependency between resources
Environment
Other
This is 🐛 Bug Report
The text was updated successfully, but these errors were encountered: