How to connect Amazon SNS to Lambda with Terraform

Hello everyone,

Today I wanted to share a quick code snippet of how you can connect Amazon SNS to AWS Lambda using Terraform. What I have seen on the web sometimes is never a complete solution, rather parts of code, which at the end, it doesn’t help you that much.

Hopefully, the below script should give you a complete overview of the same.

######## TERRAFORM PARAMETERS ########
variable "app_name" {
  description = "The name of the application being built"
  default     = "data-archiving"

}

# Customer needs to change for account specifics
variable "region_primary" {
  default = "eu-west-1"
}

# Customer needs to change for account specifics
variable "sns_topic_properties" {
  type        = object({ kms_master_key_id = string })
  description = "SNS Topic"
  default = {

    kms_master_key_id = "alias/aws/sns"

  }
}

# Customer needs to change for account specifics
variable "delete_data_lambda_function_properties" {
  type        = object({ filename = string, runtime = string, handler = string, timeout = number, cloudwatch_log_group_retention_in_days = number })
  description = "Lambda Function"
  default = {
    filename                               = "nametest.zip"
    runtime                                = "python3.8"
    handler                                = "delete_data_lambda_function.lambda_handler"
    timeout                                = 120
    cloudwatch_log_group_retention_in_days = 14
  }
}

### Tags
variable "tags" {
  description = "A map of tags to add to all resources"
  type        = map(any)
  default = {
    deployed_by = "terraform"
  }
}

######## TERRAFORM RESOURCE CREATION ########

data "aws_iam_policy_document" "lambda_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

####### Lambda Role #######
resource "aws_iam_role" "lambda_role" {
  name               = format("%s-lambda-role", var.app_name)
  assume_role_policy = data.aws_iam_policy_document.lambda_assume_role_policy.json
  tags               = var.tags
}



resource "aws_sns_topic" "sns_archive_topic" {
  name              = format("%s-topic", var.app_name)
  kms_master_key_id = var.sns_topic_properties.kms_master_key_id
  tags              = var.tags
}

data "archive_file" "python_lambda_package" {
  type        = "zip"
  source_file = "${path.module}/code/lambda_code.py"
  output_path = var.delete_data_lambda_function_properties.filename
}

resource "aws_lambda_function" "delete_data_lambda_function" {
 function_name       = format("%s-delete-data-lambda-function", var.app_name)
 filename                 = var.delete_data_lambda_function_properties.filename
 source_code_hash  = data.archive_file.python_lambda_package.output_base64sha256
 role                         = aws_iam_role.lambda_role.arn
 runtime                  = var.delete_data_lambda_function_properties.runtime
 handler                  = var.delete_data_lambda_function_properties.handler
 timeout                  = var.delete_data_lambda_function_properties.timeout
 tags                        = var.tags

  environment {
    variables = {
      AWS_REGION_PRIMARY  = var.region_primary
    }
  }
}

resource "aws_sns_topic_subscription" "lambda_topic_subscription" {
  topic_arn = aws_sns_topic.sns_archive_topic.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.delete_data_lambda_function.arn
}

resource "aws_lambda_permission" "lambda_sns_permission" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.delete_data_lambda_function.arn
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.sns_archive_topic.arn
}

resource "aws_cloudwatch_log_group" "lambda_cloudwatch_group" {
name              = format("/aws/lambda/%s", aws_lambda_function.delete_data_lambda_function.function_name)
retention_in_days = var.delete_data_lambda_function_properties.cloudwatch_log_group_retention_in_days
  tags              = var.tags
}

I know it is lengthy code, but this gives an end to end demonstration of SNS to Lambda Trigger. The most important bit in the above code are the two resources being used: aws_sns_topic_subscription and aws_lambda_permission. Those are two that gives you the link between the services, and should allow you use them.

Be aware that I am skipping also the configuration of the AWS terraform provider of this post, as it is irrelevant for what I am trying to show. Perhaps, I will demonstrate in a later blog how to do so.

Once the solution is deployed, you should see similar thing in your account.

If you have any questions or comments, leave it in the comments section of this post.

Happy coding!

Marcos Freccia

About Marcos Freccia

Sr. Database Architect focused on relational databases as well as no relational databases working currently at Amazon Web Services (AWS)

Posted on June 2, 2023, in VirtualPass and tagged , , , . Bookmark the permalink. Leave a comment.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.