amplify-cli: Cannot give postConfirmation trigger access to auth

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):

  • OS: windows 10

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!

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 28 (13 by maintainers)

Commits related to this issue

Most upvoted comments

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.

Hi @royalaid @paulsson ,

not sure if this is the correct approach? But basically my solution involves the following:

  • editing my existing post confirmation trigger lambda business logic to make use of cognito (figure 1)
  • editing the post confirmation trigger lambda’s cloudformation template, adding the LambdaExecutionRole resource’s name as an output (figure 2)
  • adding a custom resource which depends on the cognito user pool id value and the post confirmation trigger lambda’s Lambda execution Role name output value and this custom resource will create the IAM policy to access the given cognito user pool (using the user pool id reference) and attach it to the lambda’s role based on the LambdaExecutionRole name reference (figure 3)

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"
		 ]
	}
}

Running into this issue as well, but with S3 and Lambda. The workflow looks like this:

  1. Create storage with Amazon S3 and enable and add a Lambda trigger
  2. Would like to give permission to Lambda to write to S3, so we update the Lambda:
$ 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

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 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.

@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?