Describe the bug
I have created a post confirmation trigger using amplify update auth
.
I would like to give the postConfirmation trigger access to the user pool in order to get user information and perform other operations that affect the user pool.
I then used amplify update function
in order to give the post confirmation function access to the user pool.
However, an error occurs saying: "Error: Cannot add [functionName] due to a cyclic dependency" where [functionName] is the name of my function.
The postConfirmation cloudformation template file is updated with the appropriate permissions but the user pool id is not passed down as a parameter from nested-cloudformation-stack.yml
Desktop (please complete the following information):
Additional context
Invoking amplify update auth
and then adding add-to-group functionality works fine but invoking amplify update function
and then giving permissions to auth throws the error stated above.
I have tried this with @aws-amplify/cli 3.0.0 and 3.2.0, both result in the same error.
Thanks a lot!
@Jkap7788 it is a cyclic dependency as the CLI says. I'm not sure that we've a CLI supported way for this scenario, because the possibility that comes to my mind is adding a custom policy resource which depend on both resources, your user pool and the function, but the CustomResources are getting deployed within the GraphQL API scope.
it seems related to #1874 and #2076
@attilah , do you have any idea how it can be setup manually, by editing the CloudFormation template files for example?
@attilah Thanks for the reply!
I'm currently using a manual workaround for this.
Using amplify update function
to add auth permissions to cognito triggers will result in a cyclic dependency error message.
However, the correct IAM policy is added to the function's cloud formation template.
The cognito user pool id is NOT passed down as a parameter so to fix this, I manually modify the IAM policy to include the user pool id in the iam resource arn
@thedgbrt A quick and easy fix is just to manually add the user pool id into the iam policy. Not ideal but gets you unstuck quickly.
@attilah Out of curiosity, how come adding add-to-group functionality to a post confirmation trigger does not register as a cyclic dependency where as adding auth permissions via amplify update function
does cause a cyclic dependency?
@attilah I'm also running into a similar issue and would benefit from seeing an example of the setup for a custom policy you're referencing
Same problem - permission appear to be fine bu the environment variable is not set properly. What do I edit to set the environment variable to the correct userpool
I had the same issue. I ended up editing the auth's cloudformation template, rather than the function's.
Look for the comment # Updating lambda role with permissions to Cognito
. There will be a policy document section with permissions granted for group creation and adding users to groups. Add the additional policies that you want to the list.
myAuthPostConfirmationAddToGroupCognito:
Type: AWS::IAM::Policy
Properties:
PolicyName: myAuthPostConfirmationAddToGroupCognito
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- cognito-idp:AdminAddUserToGroup
- cognito-idp:GetGroup
- cognito-idp:CreateGroup
# Add your other permissions here
Resource: !GetAtt
- UserPool
- Arn
Roles:
- !Join ['',["myAuthPostConfirmation", '-', !Ref env]]
Ideally the cli would allow us to select which permissions to grant when setting up a trigger instead of assuming these defaults
I have a non-manual way to do this: I create a custom category/resource (i.e. CloudFormation stack) that depends on the function AND the user pool. The custom stack then adds policies to the function after both it and the pool are deployed. If this is interesting to people I'll publish it.
Is there any plan or way the CLI might change to support this function in the future?
@rowanu Awesome! Yes please, would love to see how you implemented it.
Turns out I was relying on a function created directly via the function category (which exports LambdaExecutionRole
) in my development environment 🙃 I have submitted a PR to export the role for all the trigger functions, so that I can demo the functionality I mentioned.
Running into this issue as well, but with S3 and Lambda. The workflow looks like this:
$ amplify update function? Please select the Lambda Function you would want to update S3Trigger45ce5c61
? Do you want to update permissions granted to this Lambda function to perform on other resources in your project? Yes
? Select the category storage
> Storage category has a resource called s3cebd22bc
? Select the operations you want to permit for s3cebd22bc create, read, update, delete
Output:
You can access the following resource attributes as environment variables from your Lambda function
var environment = process.env.ENV
var region = process.env.REGION
var storageS3cebd22bcBucketName = process.env.STORAGE_S3CEBD22BC_BUCKETNAME
Error: Cannot add S3Trigger45ce5c61 due to a cyclic dependency
at checkForCyclicDependencies (/Users/dabit/.nvm/versions/node/v10.16.3/lib/node_modules/@aws-amplify/cli/lib/extensions/amplify-helpers/update-amplify-meta.js:188:15)
at AmplifyToolkit.updateamplifyMetaAfterResourceUpdate [as _updateamplifyMetaAfterResourceUpdate] (/Users/dabit/.nvm/versions/node/v10.16.3/lib/node_modules/@aws-amplify/cli/lib/extensions/amplify-helpers/update-amplify-meta.js:101:9)
at Object.updateResource (/Users/dabit/.nvm/versions/node/v10.16.3/lib/node_modules/@aws-amplify/cli/node_modules/amplify-category-function/provider-utils/awscloudformation/index.js:242:21)
at process._tickCallback (internal/process/next_tick.js:68:7)
The use case here is resizing an image and writing back to S3
cc @kaustavghosh06
@dabit3 The Lambda trigger should already have the permissions to read write to the S3 bucket. So you don’t need to explicitly run ‘amplify update function’
Ah interesting, from my initial test it dit not. Will give it another shot and report back.
Based on my testing, the issue actually has to do with this flow only:
cyclic dependency
errorThis is probably not a high priority error since most people will probably be instead adding a lambda trigger by configuring storage (amplify update storage) and adding the function from there.
Another way around this is, when adding a new function, __not__ to add permissions for storage and then in the storage walkthrough allow the permissions to be set there.
@rowanu
I have a non-manual way to do this: I create a custom category/resource (i.e. CloudFormation stack) that depends on the function AND the user pool. The custom stack then adds policies to the function after both it and the pool are deployed. If this is interesting to people I'll publish it.
Any chance you can share how you are accomplishing this? It looks like your PR was merged.
This seems to be a very common problem with circular dependencies that many people are having.
I commented on this ticket asking for Amplify docs that sounds like what you are describing:
https://github.com/aws-amplify/amplify-cli/issues/1874#issuecomment-575254839
Thanks for any knowledge sharing!
Erik
I am also running into this issue and it appears my postConfirmation lambda is just using the default value provided for my UserPoolId output because that function never receives the output from the User Pool.
Hi @royalaid @paulsson ,
not sure if this is the correct approach? But basically my solution involves the following:
Doing the above whilst reading this section of the docs on deploying custom resources made sense to me: https://aws-amplify.github.io/docs/cli-toolchain/quickstart#custom-cloudformation-stacks
figure 1:
const cognitoIdentityServiceProvider = new CognitoIdentityServiceProvider()
figure 2:
{
....,
"Outputs": {
....,
"LambdaExecutionRole": {
"Value": {
"Ref": "LambdaExecutionRole"
}
}
}
}
figure 3:
backend-config.json
{
...,
"cognitoLambdaTriggerPermissions": {
"postConfirmationPermissions": {
"service": "Cognito-Lambda-Trigger-Permissions",
"providerPlugin": "awscloudformation",
"dependsOn": [
{
"category": "auth",
"resourceName": "customerAppCognito",
"attributes": [
"UserPoolId"
]
},
{
"category": "function",
"resourceName": "customerAppCognitoPostConfirmation",
"attributes": [
"LambdaExecutionRole"
]
}
]
}
}
}
cognitoLambdaTriggerPeromissions/postConfirmationPermissions/template.json
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Resource stack to apply cognito permissions to circular dependency lambda",
"Parameters": {
"env": {
"Type": "String"
},
"authcustomerAppCognitoUserPoolId": {
"Type": "String"
},
"functioncustomerAppCognitoPostConfirmationLambdaExecutionRole": {
"Type": "String"
}
},
"Conditions": {
},
"Resources": {
"PostConfirmationCognitoResourcesPolicy": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "post-confirmation-cognito-execution-policy",
"Roles": [
{
"Ref": "functioncustomerAppCognitoPostConfirmationLambdaExecutionRole"
}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cognito-identity:Describe*",
"cognito-identity:Get*",
"cognito-identity:List*",
"cognito-idp:Describe*",
"cognito-idp:AdminGetDevice",
"cognito-idp:AdminGetUser",
"cognito-idp:AdminList*",
"cognito-idp:List*",
"cognito-sync:Describe*",
"cognito-sync:Get*",
"cognito-sync:List*",
"iam:ListOpenIdConnectProviders",
"iam:ListRoles",
"sns:ListPlatformApplications",
"cognito-idp:ForgotPassword",
"cognito-idp:UpdateAuthEventFeedback",
"cognito-idp:UpdateResourceServer",
"cognito-idp:UpdateUserPoolClient",
"cognito-idp:AdminUpdateUserAttributes",
"cognito-idp:UpdateUserAttributes",
"cognito-idp:UpdateUserPoolDomain",
"cognito-idp:UpdateIdentityProvider",
"cognito-idp:UpdateGroup",
"cognito-idp:AdminUpdateAuthEventFeedback",
"cognito-idp:UpdateDeviceStatus",
"cognito-idp:UpdateUserPool"
],
"Resource": [
{
"Fn::Join": [
"",
[
"arn:aws:cognito-idp:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":userpool/",
{
"Ref": "authcustomerAppCognitoUserPoolId"
}
]
]
}
]
}
]
}
}
}
},
"Outputs": {
}
}
cognitoLambdaTriggerPeromissions/postConfirmationPermissions/parameters.json
{
"authcustomerAppCognitoUserPoolId": {
"Fn::GetAtt": [
"customerAppCognito",
"Outputs.UserPoolId"
]
},
"functioncustomerAppCognitoPostConfirmationLambdaExecutionRole": {
"Fn::GetAtt": [
"customerAppCognitoPostConfirmation",
"Outputs.LambdaExecutionRole"
]
}
}
Any update on this issue folks? I'm trying to update my post-confirmation lambda trigger to run some business logic when the users sign up. What's the best approach currently to implement this?
Best regards,
Kyle
@kylekirkby For your use-case, did you try adding and testing the post-confirmation auth trigger? What's the error that you're getting? The Trigger should already be populated with Cognito user-pool information which is what you're looking for out here?
Hi @kaustavghosh06 ,
Thanks for your reply! I've already got the post Confirmation Trigger added. This successfully adds the users to the "free" cognito user group - works a treat! However, I need to generate an API key for the users upon signup. For the life of me I cannot give the postConfirmation trigger lambda function permission to access my GraphQL API - I'm getting a circular dependency issue (I'm also version 4.21.0 for the CLI if that helps). Any ideas how I can achieve this? I've currently got users clicking a button to trigger a lambda function that generates the keys but would like this to be done automatically on sign up.
I did also comment on this issue: https://github.com/aws-amplify/amplify-cli/issues/1874#issuecomment-575254839
Best regards,
Kyle
@kylekirkby Yes, we're aware of this circular dependency issue and it's explained more in detail out here - https://github.com/aws-amplify/amplify-cli/issues/1874#issuecomment-606073890
Did you try out the workaround mentioned here - https://github.com/aws-amplify/amplify-cli/issues/1874#issuecomment-619316678
While we work in resolving this - can't promise an ETA at this point - you can give the workaround a try since it seems to have worked for other customers as well. Thank you!
Hi @kaustavghosh06 ,
I did try the work arounds that other users have tried but to no avail. This may work in allowing the post confirmation function to have permission to access my graphql api but I don’t get the variables added to the process. How do I go about accessing the graphql api output from the post confirmation function?
Running into the same on S3 triggers to resize.
Approaches tried:
1)Added trigger as part of S3 creation.
2)Also tried adding a function, and then adding as a trigger.
Both the cases "Access Denied" when writing back to s3.
Tried adding permissions and ran into cyclic dependency.
cc:
@kaustavghosh06
@dabit3
I have the same problem and tried the same as @kkrao2301 — no solution.
I was having this same issue and @danielblignaut's solution here worked wonders. As a matter of fact, it was simpler than that because I only needed to edit backend-config.json
and create the CloudFormation template for that resource. The Outputs
key in his figure 2 was already added to my lambda template and the parameters.json
wasn't needed because the CLI created them for me automatically in nested-cloudformation-stack.yml
.
I did have to amplify env checkout {your-env}
for the CLI to pick up the changes to backend-config.json
.
I was having this issue. And just added the permission like noted here and then did amplify push
and all is well.
Few had proposed the solution and @danielblignaut straigh forward answer helped me to solve the issue. xoxo
Most helpful comment
Hi @royalaid @paulsson ,
not sure if this is the correct approach? But basically my solution involves the following:
Doing the above whilst reading this section of the docs on deploying custom resources made sense to me: https://aws-amplify.github.io/docs/cli-toolchain/quickstart#custom-cloudformation-stacks
figure 1:
figure 2:
figure 3:
backend-config.json
cognitoLambdaTriggerPeromissions/postConfirmationPermissions/template.json
cognitoLambdaTriggerPeromissions/postConfirmationPermissions/parameters.json