Cognito "PreSignUp invocation failed due to configuration" despite having invoke permissions well configured

Viewed 933

I currently have a Cognito user pool configured to trigger a pre sign up lambda. Right now I am setting up the staging environment, and I have the exact same setup on dev (which works). I know it is the same because I am creating both envs out of the same terraform files.

I have already associated the invoke permissions with the lambda function, which is very often the cause for this error message. Everything looks the same in both environments, except that I get "PreSignUp invocation failed due to configuration" when I try to sign up a new user from my new staging environment.

  • I have tried to remove and re-associate the trigger manually, from the console, still, it doesn't work
  • I have compared every possible setting I can think of, including "App client" configs. They are really the same
  • I tried editing the lambda code in order to "force" it to update

Can it be AWS taking too long to invalidate the permissions cache? So far I can only believe this is a bug from AWS...

Any ideas!?

2 Answers

There appears to be a race condition with permissions not being attached on the first deployment.

I was able to reproduce this with cloudformation.

Deploying a stack with the same config twice appears to "fix" the permissions issue.

I actually added a 10-second delay on the permissions attachment and it solved my first deployment issue...

I hope this helps others who run into this issue.

    # Hack to fix Cloudformation bug
    # AWS::Lambda::Permission will not attach correctly on first deployment unless "delay" is used
    # DependsOn & every other thing did not work... ¯\_(ツ)_/¯
    CustomResourceDelay:
      Type: Custom::Delay
      DependsOn:
        - PostConfirmationLambdaFunction
        - CustomMessageLambdaFunction
        - CognitoUserPool
      Properties:
        ServiceToken: !GetAtt CustomResourceDelayFunction.Arn
        SecondsToWait: 10
    CustomResourceDelayFunctionRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement: [{ "Effect":"Allow","Principal":{"Service":["lambda.amazonaws.com"]},"Action":["sts:AssumeRole"] }]
        Policies:
          - PolicyName: !Sub "${AWS::StackName}-delay-lambda-logs"
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action: [ logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents ]
                  Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}*:*
    CustomResourceDelayFunction:
      Type: AWS::Lambda::Function
      Properties:
        Handler: index.handler
        Description: Wait for N seconds custom resource for stack debounce
        Timeout: 120
        Role: !GetAtt CustomResourceDelayFunctionRole.Arn
        Runtime: nodejs12.x
        Code:
          ZipFile: |
            const { send, SUCCESS } = require('cfn-response')
            exports.handler = (event, context, callback) => {
              if (event.RequestType !== 'Create') {
                return send(event, context, SUCCESS)
              }
              const timeout = (event.ResourceProperties.SecondsToWait || 10) * 1000
              setTimeout(() => send(event, context, SUCCESS), timeout)
            }

    # ------------------------- Roles & Permissions for cognito resources ---------------------------
    CognitoTriggerPostConfirmationInvokePermission:
      Type: AWS::Lambda::Permission
      ## CustomResourceDelay needed to property attach permission
      DependsOn: [ CustomResourceDelay ]
      Properties:
        Action: lambda:InvokeFunction
        FunctionName: !GetAtt PostConfirmationLambdaFunction.Arn
        Principal: cognito-idp.amazonaws.com
        SourceArn: !GetAtt CognitoUserPool.Arn

In my situation the problem was caused by the execution permissions of the Lambda function: While there was a role configured, that role was empty due to some unrelated changes.

Making sure the role actually had permissions to do the logging and all the other things that the function was trying to do made things work again for me.

Related