Search code examples
amazon-cognitoaws-cdkaws-cdk-typescript

How do I grant another account rights to create users in cognito pool?


How would I go about granting a lambda function in another account access to create users in cognito user pool?

So far I've tried with this:

 const cognitoProcessorRolePrincipal = new AccountPrincipal(getEnvVars(this).THE_OTHER_ACCOUNT);

    const cognitoProcessorRole = new Role(this, `${getEnvWithApp(this)}-cognito-processor-role`, {
      assumedBy: cognitoProcessorRolePrincipal,
      roleName: `${getEnvWithApp(this)}-cognito-processor-role`,
      inlinePolicies: {
        cognitoPolicy: new PolicyDocument({
          statements: [new PolicyStatement({
            effect: Effect.ALLOW,
            actions: [
              "cognito-idp:AdminCreateUser",
            ],
            resources: [this.userPool.userPoolArn]
          })]
        })
      }
    })

But I keep getting this error from the other service. So the role is assumed correctly, but there are no rights to create users.

"AccessDeniedException: User: arn:aws:sts::OMITEDcognito-processor-role/OMITED is not authorized to perform: cognito-idp:AdminCreateUser on resource: arn:aws:cognito-idp:us-west-1:OMITED:userpool/OMITED because no identity-based policy allows the cognito-idp:AdminCreateUser action\n\tstatus code: 400, request id: OMITED"

Ive already tried granting the rights like this,

this.userPool.grant(cognitoProcessorRole, 
      "cognito-idp:AdminCreateUser",
    )

but to no avail.


Solution

  • On the account that owns the cognito instance you will need to create a Role that grants another account access to it:

    new Role(this, 'allowOtherAccountRole', {
      roleName: 'TheRoleName',
      assumedBy: new AccountPrincipal(accountId), // <~ put the account id of the other account here
      inlinePolicies: { delegation: new PolicyDocument({
          statements: [
            ...
          ]
        })
      }
    });
    

    the statements are something like this

    const allowAll = new PolicyStatement();
    allowAll.addActions('cognito:*');
    allowAll.addResources('the:cognito:arn:here');
    statements.push(allowAll);
    

    Now on the other account (the one that wants to access the other account's cognito), you need to use STS to assume a role:

     const { Credentials } = await this.sts.assumeRole({
        RoleArn: `arn:aws:iam::${theCognitoAccountId}:role/TheRoleName`,
        RoleSessionName: `cross-account-${Date.now()}`
    });
    

    and use the Credentials to configure the Cognito client.

    Also, remember to grant the lambda permissions to assume this role.

    const allowAssumeRole = new PolicyStatement();
    allowAssumeRole.addActions('sts:AssumeRole');
    allowAssumeRole.addResources(`arn:aws:iam::${theCognitoAccountId}:role/TheRoleName`);
    lambda.role.addToPrincipalPolicy(allowAssumeRole);