pull items from cognito to dynamodb

0

i created a terraform that build http api gateway and connect to cognito. everything work well. i wanted to pull the user_id + email and watch them on dynamodb, so i created a lambda function that do just that and attached it to cognito as a trigger.

i gave all the necessary permmisions through IAM role, and for some reason nothing is happening.(there are no lambda logs errors)

i tried to create another lambda function with the same permissions and with the same code - and when i attach it manually to cognito - it works!

why is it that when i create the lambda function on terraform and attach to it all it need - nothing happened, and when i attach it manually - it works?

please share your thoughts with me

my dynamodb

resource "aws_dynamodb_table" "my_table" {
  name         = "my-table"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "user_id"

  attribute {
    name = "user_id"
    type = "S"
  }
}

my cognito

resource "aws_cognito_user_pool" "user_pool" {
  name = "user-pool"
  username_configuration {
    case_sensitive = false
  }
  alias_attributes = ["email", "preferred_username"]

  auto_verified_attributes = ["email"]

  password_policy {
    minimum_length                   = 8
    temporary_password_validity_days = 7
  }
  verification_message_template {
    default_email_option = "CONFIRM_WITH_CODE"
    email_subject        = "Account Confirmation"
    email_message        = "Your confirmation code is {####}"
  }
  lambda_config {
    post_authentication = aws_lambda_function.myfunction.arn
  }
  schema {
    attribute_data_type      = "String"
    developer_only_attribute = false
    mutable                  = true
    name                     = "email"
    required                 = true

    string_attribute_constraints {
      min_length = 1
      max_length = 256
    }
  }
}

resource "aws_cognito_user_pool_client" "client" {
  name = "demo-app-cognito-client"

  user_pool_id                         = aws_cognito_user_pool.user_pool.id
  generate_secret                      = true
  supported_identity_providers         = ["COGNITO"]
  refresh_token_validity               = 90
  allowed_oauth_flows                  = ["code", "implicit"]
  allowed_oauth_scopes                 = ["phone", "email", "openid", "profile", "aws.cognito.signin.user.admin"]
  allowed_oauth_flows_user_pool_client = true
  prevent_user_existence_errors        = "ENABLED"
  callback_urls                        = ["${aws_apigatewayv2_stage.lambda_stage.invoke_url}/"]
  explicit_auth_flows = [
    "ALLOW_REFRESH_TOKEN_AUTH",
    "ALLOW_USER_PASSWORD_AUTH",
    "ALLOW_ADMIN_USER_PASSWORD_AUTH"
  ]

}
resource "aws_cognito_user_pool_domain" "cognito-domain" {
  domain       = var.domain_prefix
  user_pool_id = aws_cognito_user_pool.user_pool.id
}

my IAM

resource "aws_iam_role" "cognito_role" {
  name               = "cognito_role"
  assume_role_policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Sid" : "",
        "Effect" : "Allow",
        "Principal" : {
          "Service" : "lambda.amazonaws.com"
        },
        "Action" : "sts:AssumeRole"
      }
    ]
  })
}

resource "aws_iam_policy" "cognito_project_policy" {
  name   = "CognitoProjectPolicy"
  policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Action" : [
          "ec2:CreateNetworkInterface",
          "ec2:DescribeNetworkInterfaces",
          "ec2:DeleteNetworkInterface",
          "ec2:DescribeInstances",
          "ec2:AttachNetworkInterface",
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:DescribeLogGroups",
          "logs:DescribeLogStreams",
          "logs:PutLogEvents",
          "logs:GetLogEvents",
          "logs:FilterLogEvents",
          "dynamodb:DeleteItem",
          "dynamodb:GetItem",
          "dynamodb:PutItem",
          "dynamodb:Query",
          "dynamodb:UpdateItem"
        ],
        "Resource": "*"
      }
    ]
  })
}

# IAM Role Policy Attachment for "cognito-role"
resource "aws_iam_role_policy_attachment" "cognito_project_policy_attach" {
  role       = aws_iam_role.cognito_role.name
  policy_arn = aws_iam_policy.cognito_project_policy.arn
}

# IAM Role Policy Attachment AmazonDynamoDBFullAccess
resource "aws_iam_role_policy_attachment" "AmazonDynamoDBFullAccess" {
  role       = aws_iam_role.cognito_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
}

# IAM Role Policy Attachment AmazonCognitoPowerUser
resource "aws_iam_role_policy_attachment" "AmazonCognitoPowerUser" {
  role       = aws_iam_role.cognito_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonCognitoPowerUser"
}

# IAM Role Policy Attachment AmazonCognitoDeveloperAuthenticatedIdentities
resource "aws_iam_role_policy_attachment" "AmazonCognitoDeveloperAuthenticatedIdentities" {
  role       = aws_iam_role.cognito_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonCognitoDeveloperAuthenticatedIdentities"
}

my lambda terraform

resource "aws_lambda_function" "myfunction" {
  filename         = "myfunction.zip"
  function_name    = "myfunction"
  role             = aws_iam_role.cognito_role.arn
  handler          = "myfunction.lambda_handler"
  runtime          = "python3.10"
  timeout          = 300
  source_code_hash = data.archive_file.post_authentication.output_base64sha256

  environment {
    variables = {
      DYNAMODB_TABLE = aws_dynamodb_table.my_table.name
    }
  }
  
  vpc_config {
    subnet_ids         = aws_subnet.private_subnets[*].id
    security_group_ids = [aws_security_group.sg.id]
  }
}

resource "aws_lambda_permission" "store_user_to_dynamodb_permission" {
  statement_id  = "AllowExecutionFromCognito"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.myfunction.function_name
  principal     = "cognito-idp.amazonaws.com"
  source_arn    = aws_cognito_user_pool.user_pool.arn
}

my lambda function

import json
import boto3
from datetime import datetime

dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):
    try:
        user_name = event['userName']
        trigger_source = event['triggerSource']
        user_attributes = event['request']['userAttributes']
        email = user_attributes.get('email', '')
        login_time = datetime.now().isoformat()
        status = 'success' if trigger_source == 'PostAuthentication_Authentication' else 'failed'

        table = dynamodb.Table('users')
        table.put_item(
            Item={
                'user_id': user_name,
                'email': email,
                'login_time': login_time,
                'status': status
            }
        )

        return event
    except KeyError as e:
        return {
            'errorMessage': str(e),
            'errorType': 'KeyError',
            'requestId': context.aws_request_id}
  • i tried to create another lambda function with the same permissions and with the same code - and when i attach it manually to cognito - it works!

    What did you attach manually?

  • Hi Gary. i created another Lambda function with the same code and permissions - AmazonDynamoDBFullAccess AmazonCognitoPowerUser AmazonCognitoDeveloperAuthenticatedIdentities

    and added it in the cognito as a trigger(added it to the original lambda that i created on terraform)

1 Answer
-1

Hi SR, did you try to invoke the Lambda that you created via Terraform through AWS CLI invoke for lambda: https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html ?

The payload to construct for this manual call is described here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-post-authentication.html#cognito-user-pools-lambda-trigger-syntax-post-auth

When you get the CLI invoke to work, then you can try to activate it again from Cognito. Again then go the AWS console for Lambdas to see if your Lambda was properly triggered by Cognito.

Best,

Didier

profile pictureAWS
EXPERT
answered 10 months ago
  • Hi! yes i did, got all the right outputs, still get only - "Completed. Read capacity units consumed: 2" without the ability to see those items...

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions