aws-amplify / amplify-backend

Home to all tools related to Amplify's code-first DX (Gen 2) for building fullstack apps on AWS
Apache License 2.0
188 stars 64 forks source link

Insufficient permissions to execute the `AdminLinkProviderForUser` command #1382

Open eechih opened 7 months ago

eechih commented 7 months ago

Environment information

System:
  OS: Linux 6.5 Ubuntu 22.04.4 LTS 22.04.4 LTS (Jammy Jellyfish)
  CPU: (12) x64 Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz
  Memory: 53.89 GB / 62.64 GB
  Shell: /usr/bin/zsh
Binaries:
  Node: 18.15.0 - ~/.nvm/versions/node/v18.15.0/bin/node
  Yarn: 1.22.19 - ~/.nvm/versions/node/v18.15.0/bin/yarn
  npm: 9.6.2 - ~/.nvm/versions/node/v18.15.0/bin/npm
  pnpm: 8.5.1 - ~/.nvm/versions/node/v18.15.0/bin/pnpm
NPM Packages:
  @aws-amplify/backend: 0.13.2
  @aws-amplify/backend-cli: 0.13.0
  aws-amplify: 6.0.30
  aws-cdk: 2.138.0
  aws-cdk-lib: 2.138.0
  typescript: 5.4.5
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables

Description

I have a function that needs to use the AdminLinkProviderForUserCommand command, but the "manageUsers" action does not seem to contain the 'cognito-idp:AdminLinkProviderForUser' action.

// amplify/auth/resource.ts

import { linkProviderForUserFunction } from '@/amplify/functions/link-provider-for-user/resource'

export const auth = defineAuth({
  ...
  access: allow => [
    allow.resource(linkProviderForUserFunction).to(['manageUsers']),
  ],
})
// amplify/functions/link-provider-for-user/handler.ts

import { env } from '$amplify/env/link-provider-for-user'
import type { Schema } from '@/amplify/data/resource'
import {
  AdminLinkProviderForUserCommand,
  CognitoIdentityProviderClient,
  InvalidParameterException,
} from '@aws-sdk/client-cognito-identity-provider'
import { AppSyncIdentityCognito } from 'aws-lambda'

const client = new CognitoIdentityProviderClient()

export const handler: Schema['linkProviderForUser']['functionHandler'] =
  async event => {
    const { providerName, providerUserId } = event.arguments
    const identity = event.identity as AppSyncIdentityCognito

    const command = new AdminLinkProviderForUserCommand({
      UserPoolId: env.AMPLIFY_AUTH_USERPOOL_ID,
      DestinationUser: {
        ProviderName: 'Cognito',
        ProviderAttributeValue: identity.username,
      },
      SourceUser: {
        ProviderName: providerName,
        ProviderAttributeName: 'Cognito_Subject',
        ProviderAttributeValue: providerUserId,
      },
    })

    const response = await client.send(command)
    ...
  }

The following error occurs:

2024-04-26T01:10:30.391Z    5eada46c-eea6-4093-8b5e-0f4557193695    ERROR   Invoke Error    {
    "errorType": "AccessDeniedException",
    "errorMessage": "User: arn:aws:sts::089370838833:assumed-role/amplify-drinkshopbackend--linkproviderforuserlambda-Hji1xUz2DDsw/amplify-drinkshopbackend--linkproviderforuserlambd-GNHSJOXwO4To is not authorized to perform: cognito-idp:AdminLinkProviderForUser on resource: arn:aws:cognito-idp:us-east-1:089370838833:userpool/us-east-1_SPrRZH9Kd because no identity-based policy allows the cognito-idp:AdminLinkProviderForUser action",
    ...
}

Is there any solution? Thanks.

ykethan commented 7 months ago

Hey @eechih, thank you for reaching out. The issue appears to be similar to https://github.com/aws-amplify/amplify-backend/issues/1375, refer to the comment https://github.com/aws-amplify/amplify-backend/issues/1375#issuecomment-2079388509 using override to add the permissions Marking this as feature request.

eechih commented 7 months ago

@ykethan Thanks a lot, that worked :)

MyNameIsTakenOMG commented 3 months ago

Hi @ykethan , I checked the doc, seems like we still don't have the AdminLinkProviderForUser option, and that could cause some issue, for example when we try to assign this action or permission to pre-signup trigger, right? And I don't think we can directly access this trigger using backend.auth.resources and add the action manually. So what is your opinion?

Update:

I succeeded to add this AdminLinkProviderForUser permission to the lambda trigger by importing the lambda resource into the amplify backend, and then added an inline policy by following your workaround, many thanks!

Btw, I think it would be better to add at least a note to tell devs that if they want to configure pre-signup or post-confirmation triggers, they can import them into amplify backend like other normal lambda function.