Skip to content
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

amplify update function - auth cyclic dependency issue #13717

Closed
2 tasks done
pr0g opened this issue Apr 16, 2024 · 11 comments
Closed
2 tasks done

amplify update function - auth cyclic dependency issue #13717

pr0g opened this issue Apr 16, 2024 · 11 comments
Labels
auth Issues tied to the auth category of the CLI pending-triage Issue is pending triage

Comments

@pr0g
Copy link

pr0g commented Apr 16, 2024

How did you install the Amplify CLI?

npm

If applicable, what version of Node.js are you using?

v16.20.2

Amplify CLI Version

12.11.0

What operating system are you using?

macOS

Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes made.

No

Describe the bug

I added a Cognito Lambda trigger using amplify add auth. I now want to add permissions to that function so it can access Cognito (auth).

  1. I run amplify update function,
  2. Select the new function (a post authentication trigger)
  3. Select Resource access permissions
  4. Select auth (api is already selected and working)
  5. Select the resource for our app
  6. Select Query and Mutation
  7. Select the auth resource for our app
  8. Select read operations (for just getting read access to Cognito)
  9. Hit enter

I then get this error:

You can access the following resource attributes as environment variables from your Lambda function
	API_<APP>CLIENT_GRAPHQLAPIENDPOINTOUTPUT
	API_<APP>CLIENT_GRAPHQLAPIIDOUTPUT
	AUTH_<APP>_USERPOOLID
Error: Cannot add <app>PostAuthentication due to a cyclic dependency
    at checkForCyclicDependencies (/snapshot/amplify-cli/build/node_modules/@aws-amplify/cli-internal/lib/extensions/amplify-helpers/update-amplify-meta.js:252:15)
    at AmplifyToolkit.updateamplifyMetaAfterResourceUpdate (/snapshot/amplify-cli/build/node_modules/@aws-amplify/cli-internal/lib/extensions/amplify-helpers/update-amplify-meta.js:159:9)
    at updateFunctionResource (/snapshot/amplify-cli/build/node_modules/@aws-amplify/amplify-category-function/lib/provider-utils/awscloudformation/index.js:160:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.executeAmplifyCommand (/snapshot/amplify-cli/build/node_modules/@aws-amplify/amplify-category-function/lib/index.js:277:5)
    at async executePluginModuleCommand (/snapshot/amplify-cli/build/node_modules/@aws-amplify/cli-internal/lib/execution-manager.js:139:5)
    at async executeCommand (/snapshot/amplify-cli/build/node_modules/@aws-amplify/cli-internal/lib/execution-manager.js:37:9)
    at async Object.run (/snapshot/amplify-cli/build/node_modules/@aws-amplify/cli-internal/lib/index.js:121:5)

I have checked amplify/cli.json and I have "breakcirculardependency" set to true

...
"auth": {
    "enablecaseinsensitivity": true,
    "useinclusiveterminology": true,
    "breakcirculardependency": true
}
...

I've tried to make manual edits to work around the Amplify CLI, but unfortunately hit errors with the CloudFormation stack deploy

🛑 The following resources failed to deploy:
Resource Name: function<app>PostAuthentication (AWS::CloudFormation::Stack)
Event Type: update
Reason: Parameters: [auth<app>Userpoolid] do not exist in the template
URL: ....

🛑 Resource is not in the state stackUpdateComplete
Name: function<app>PostAuthentication (AWS::CloudFormation::Stack), Event Type: update, Reason: Parameters: [auth<app>Userpoolid] do not exist in the template, IsCustomResource: false

Is there a way I can add auth access to my new Cognito Lambda trigger function? Any help/workaround would be hugely appreciated!

Expected behavior

amplify update function allows auth to be added without hitting Error: Cannot add <app>PostAuthentication due to a cyclic dependency error

Reproduction steps

See above

Project Identifier

--send-report failed

✅ Report saved: /var/folders/lm/dkwtwmzx30j144_pfh714ncm0000gp/T/revuclient/report-1713303709454.zip

⠹ Sending zip
DiagnoseReportUploadError
✖ Sending zip

Log output

amplify-cli-2024-04-16.log

Additional information

If there's a way to do this manually as a temporary workaround that would be great to know!

Before submitting, please confirm:

  • I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
  • I have removed any sensitive information from my code snippets and submission.
@pr0g pr0g added the pending-triage Issue is pending triage label Apr 16, 2024
@pr0g
Copy link
Author

pr0g commented Apr 16, 2024

Tagging @josefaidt in case you have any ideas. I saw your comment on a similar issue a little while ago. Thank you!

@ykethan
Copy link
Member

ykethan commented Apr 16, 2024

@pr0g from the name it appears you are trying to creating a PostAuthentication trigger and add permission to Cognito/Auth resource. By default a Cognito trigger should have access to the Auth resource. Trying to add the auth permission again will result in a Circular dependancy error. The Lambda event should contain the Cognito parameters, refer to the documentation providing an sample event structure.

@ykethan ykethan added auth Issues tied to the auth category of the CLI pending-response Issue is pending response from the issue author labels Apr 16, 2024
@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

Thank you very much for your reply @ykethan. I see, that makes total sense, I'll double check what wasn't working for me then as I'd perhaps wrongly assumed it was the authorization. I'm essentially trying to lookup the Cognito real name from the username to store along with some other data in DynamoDB. I'll have a look today with fresh eyes and report back with an update. Thanks for the pointer 👍

@github-actions github-actions bot removed the pending-response Issue is pending response from the issue author label Apr 17, 2024
@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

Okay I followed up with this and I still can't seem to get it to work.

When first adding the trigger, no auth logic is added for being able to access Cognito.

If I call some code like...

 const client = new CognitoIdentityProviderClient({});
  const result = await client.send(new AdminGetUserCommand({
    UserPoolId: process.env.AUTH_<app>_USERPOOLID,
    Username: username
  }));

I get the error message:

undefined WARN Unable to get user pool ID from environment - will need to be passed as parameter

If I then do amplify update function, and provide the function access to auth (as described earlier, where I hit the circular dependency error), when the Cognito Lambda trigger runs, the environment variable is set, but isn't resolved to the correct value (it's just the placeholder)

// print
INFO UserPoolID: auth<app>UserPoolId

instead of...

// print
INFO UserPoolID: eu-west-2_<id>

If I look in the Lambda function Environment variables section in the AWS Console, I see auth<app>UserPoolId for AUTH_<app>_USERPOOLID instead of eu-west-2_<id> too (which is what I see in other Lambda functions I've added in the past).

I see that I can access the User Pool Id from the event parameter from the docs you shared (event.userPoolId), it's just we have several helper functions that rely on process.env.AUTH_<app>_USERPOOLID being available.

I guess my two workaround options are:

  1. Refactor our helper functions to accept the User Pool Id as an optional parameter (to avoid having to update lots of callsites).
  2. Update the Lambda function environment variables with the correct User Pool Id from the AWS console (this is likely a bad idea though as this may create drift and cause what Amplify thinks is the value and what is actually the deployed value to be out of sync 🤔).

In the Post Authentication CloudFormation template, I don't see any of the permissions listed to access Cognito unless I run amplify update function and add auth. E.g.:

  "Effect": "Allow",
  "Action": [
    "cognito-identity:Describe*",
    "cognito-identity:Get*",
    "cognito-identity:List*",
    etc...

Which is surprising to me, I don't know how the Lambda function would have acccess without that.

Sorry if I'm missing something super obvious, but if you could help me understand the context a bit better I'd really appreciate it.

Thanks again!

@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

I tried the refactor approach I described but no luck... When I call:

const client = new CognitoIdentityProviderClient({});
const result = await client.send(new AdminGetUserCommand({
  UserPoolId: userPoolId,
  Username: username
}));

I get this error:

{
    "name": "AccessDeniedException",
    "$fault": "client",
    "$metadata": {
        "httpStatusCode": 400,
        "requestId": "300877e0-3636-4520-8527-5604addaae85",
        "attempts": 1,
        "totalRetryDelay": 0
    },
    "__type": "AccessDeniedException",
    "message": "User: arn:...:assumed-role/<app>PostAuthentication-<env>/<app>PostAuthentication-<env> is not authorized to perform: cognito-idp:AdminGetUser on resource: arn:aws:cognito-idp:eu-west-2:<account>:userpool/<user-pool-id> because no identity-based policy allows the cognito-idp:AdminGetUser action"
}

It's really odd because we do have CustomMessage, PostConfirmation and PreSignup already which do seem to work correctly, so I don't know if something has changed in the Amplify CLI since they were originally created (quite a while ago). I've been trying to compare the ..cloudformation-template.json files without great success.

Is there anything else I can do to debug what's going wrong and why I don't have valid permissions to call Cognito from this Cognito Lambda trigger?

@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

As a quick workaround I've found adding the below to <app>PostAuthentication-cloudformation-template.json works, but right now the user pool id is hardcoded, so I'll need to fix this soon.

            {
              "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"
              ],
              "Resource": "arn:aws:cognito-idp:eu-west-2:<account-id>:userpool/<user-pool-id>"
            }

It seems something similar to this should be added by default when creating the Cognito Lambda trigger perhaps?

@ykethan
Copy link
Member

ykethan commented Apr 17, 2024

@pr0g the Lambda function requires additional permission we can add the permissions on the custom-policies.json file present in the function folder or modify the function template. It best practise to add resource-based policies with minimal actions that invocation service requires. Please refer to documentation providing additional information.

@ykethan ykethan added the pending-response Issue is pending response from the issue author label Apr 17, 2024
@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

Hi @ykethan, thanks for getting back to me and thanks for the doc link, I'll have a read through soon.

I just want to check in the custom-policies.json file, can it refer to the environment variable for the userPool ID?

So something like this...

{
  "Effect": "Allow",
  "Action": [
    "cognito-identity:Describe*",
    .....
  ],
  "Resource": [
    {
      "Fn::Join": [
        "",
        [
          "arn:aws:cognito-idp:",
          {
            "Ref": "AWS::Region"
          },
          ":",
          {
            "Ref": "AWS::AccountId"
          },
          ":userpool/",
          {
            "Ref": "authrevuUserPoolId"
          }
        ]
      ]
    }
  ]
}

The issue I was finding was the environment variable wasn't automatically populated for the Cognito Lambda trigger (this normally happens when adding amplify update function and adjusting the auth permissions). Would you recommend providing an explicity environment variable and setting that per environment? Or should it just work out of the box?

For example I don't see AUTH_<APP>_USERPOOLID below in the Post Authentication function like the below (I do see the GRAPHQL ones as I added them using amplify update function).

/* Amplify Params - DO NOT EDIT
	API_<app>CLIENT_GRAPHQLAPIENDPOINTOUTPUT
	API_<app>CLIENT_GRAPHQLAPIIDOUTPUT
	AUTH_<APP>_USERPOOLID
	ENV
	REGION
Amplify Params - DO NOT EDIT */

@github-actions github-actions bot removed the pending-response Issue is pending response from the issue author label Apr 17, 2024
@ykethan
Copy link
Member

ykethan commented Apr 17, 2024

@pr0g The env variable should be available using ${env}, refer to the example on the documentation.
If you are trying to utilize the the userpoolId as part of your SDK calls this should already be present on the Lambda event. Refer to common Cognito Lambda trigger parameters on the AWS documentation.

@ykethan ykethan added the pending-response Issue is pending response from the issue author label Apr 17, 2024
@pr0g
Copy link
Author

pr0g commented Apr 17, 2024

@ykethan Okay good to know, I just guess there's a subtle difference between a Cognito Lambda trigger function, and a regular Lambda function, in terms of how you grant them permissions to Cognito, which was what tripped me up. It's a little confusing, but glad it's working now. I wound up modifying custom-policies.json to look like this:

[
  {
    "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"
    ],
    "Resource": [
      "arn:aws:cognito-idp:eu-west-2:*:userpool/*"
    ]
  }
]

I could refine it in future to use the ${env} variable you mentioned, but I think this is okay for now. I think the thing to be clear on is Cognito access did not, and could not, have worked without the above, if you're not able to use amplify update function in this case.

Thank you for your help, we can close this issue now.

@pr0g pr0g closed this as completed Apr 17, 2024
@github-actions github-actions bot removed the pending-response Issue is pending response from the issue author label Apr 17, 2024
Copy link

This issue is now closed. Comments on closed issues are hard for our team to see.
If you need more assistance, please open a new issue that references this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auth Issues tied to the auth category of the CLI pending-triage Issue is pending triage
Projects
None yet
Development

No branches or pull requests

2 participants