Linking Lambda Function to an Exiting User Pool

Hi all,

I’m currently trying to link an existing Cognito Pool with a new Lambda Function to augment some of the functionality. When I deploy the function though, it creates a new User Pool with the same name as the existing one. Googling and reading the forums didn’t turn up anything about linking an existing User Pool instead of creating a new one. Is this possible to do?

provider:
  stage: dev
  region: us-east-2
  name: aws
  runtime: nodejs6.10
functions:
  preSignUp:
    handler: preSignUp.handler
    events:
      - cognitoUserPool:
            userPool: user-pool-name
            trigger: PreSignUp

Serverless uses CloudFormation to deploy stacks and in CloudFormation the User Pool triggers are part of the User Pool configuration. This means you can’t configure an existing user pool to use your function by setting cognitoUserPool as an event source for your functions.

You can still use the Lambdas with the existing User Pool but you need to,

  1. Manually configure the User Pool to use the Lambda as a trigger, or
  2. Use cross stack references to export the Lambda function ARN from this stack then import the ARN into the stack that deploys the User Pool

I am doing this, but the setup is probably a bit weird.

I have a separate CloudFormation stack that manages the Cognito User Pool. Let’s say that stack is named cognito-stack and it outputs the ARN of the user pool like this :

Resources:
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties: 
      <whatever else you need, important part is LambdaConfig>
      LambdaConfig:
        PreSignUp: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:myservice-${stage}-cognito-pre-signup'

Outputs:
  UserPoolArn:
    Value: !GetAtt UserPool.Arn
    Export:
      Name: !Sub myservice-${stage}:user-pool-arn

Then my serverless.yml will create a service named myservice-${stage} and set up the Cognito trigger like this:

service: myservice

custom:
 stage: ${opt:stage, self:provider.stage}
 userPoolArn: ${cf:cognito-stack.UserPoolArn}

functions:
  cognito-pre-signup:
    handler: <your handler here>

resources:
  Resources:
    PreSignupTriggerInvokePermission:
      Type: AWS::Lambda::Permission
      DependsOn: CognitoDashpreDashsignupLambdaFunction
      Properties:
        Action: lambda:InvokeFunction
        Principal: cognito-idp.amazonaws.com
        SourceArn: ${self:custom.userPoolArn}
        FunctionName: ${self:service}-${self:custom.stage}-cognito-pre-signup

It works cause the Cognito User Pool LambdaConfig does not care if the ARN you are referencing is an existing lambda function or not (AWS is not consistent about this). So if all you do is deploy the cognito-stack you will have problems cause the PreSignUp trigger will fail.

The important bit in the serverless.yml is the AWS::Lambda::Permission to allow Cognito to execute your Lambda function. Without it, if you go into the Cognito console, it will look like your lambda is connected to the user pool, but it won’t run. CognitoDashpreDashsignupLambdaFunction is the logical name of the lambda function generated by Serverless. The SourceArn comes from the custom variable which is set by referencing the exported CloudFormation Cognito user pool ARN.

This setup works for me, hopefully you can tweak it for your use case.

1 Like

SOLVED.
I was having same issue when i was deploying with serverless version 1.42. But I tried with serverless version 1.48 and it got fixed.