Event bus name not registering when attempting to connect eventbridge and lambda using terraform - aws-lambda

I am attempting to create an Eventbridge that will get notifications from Datadog, and trigger a lambda function to store the notifications to an S3 bucket. This is all going to be done through Terraform.
The following is the code I have written:
###################################
# Eventbridge Integration to Lambda
###################################
data "aws_cloudwatch_event_source" "datadog_event_source" {
name_prefix = var.spog_event_bus_name # aws.partner/datadog.com/my_eventbus
}
resource "aws_cloudwatch_event_bus" "datadog_event_bus" {
name = data.aws_cloudwatch_event_source.datadog_event_source.name
event_source_name = data.aws_cloudwatch_event_source.datadog_event_source.name
}
resource "aws_cloudwatch_event_rule" "spog_cloudwatch_rule" {
name = "spog_cloudwatch_rule"
event_bus_name = aws_cloudwatch_event_bus.datadog_event_bus.name
event_pattern = <<EOF
{
"account": [
"${var.aws_account_id}"
]
}
EOF
}
resource "aws_cloudwatch_event_target" "spog_cloudwatch_event_target" {
rule = aws_cloudwatch_event_rule.spog_cloudwatch_rule.name
target_id = aws_lambda_function.write_datadog_events.function_name
arn = aws_lambda_function.write_datadog_events.arn
}
resource "aws_lambda_permission" "spog_allow_cloudwatch" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.write_datadog_events.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.spog_cloudwatch_rule.arn
}
Here, the write_datadog_events is the lambda function to store the notifications.
The build succeeds, but when I try to apply the plan, I get an error saying that "validationException: EventBus name starting with 'aws.' is not valid". From inspecting the aws console, it seems that the actual eventbridge and rule are created successfully, but the event bus name is not registered properly on the eventbridge. The event bus name only says default, and I thought by changing the event_bus_name value within aws_cloudwatch_event_rule, it would not be default, but I was wrong.
Can anyone help me out with this. The lambda function itself is not wrong (since I ran a test case on it), it seems that the core issue is eventbridge not registering my event bus name. Also, although the rule is generated, the event bus is never generated.
Thanks for your help.

Related

Triggering a Lambda once a DMS Replication Task has completed in Terraform

I would like to trigger a Lambda once an RDS Replication Task has successfully completed. I have the following Terraform code, which successfully creates all the assets, but my Lambda is not being triggered.
resource "aws_dms_event_subscription" "my_event_subscription" {
enabled = true
event_categories = ["state change"]
name = "my-event-subscription"
sns_topic_arn = aws_sns_topic.my_event_subscription_topic.arn
source_ids = ["my-replication-task"]
source_type = "replication-task"
}
resource "aws_sns_topic" "my_event_subscription_topic" {
name = "my-event-subscription-topic"
}
resource "aws_sns_topic_subscription" "my_event_subscription_topic_subscription" {
topic_arn = aws_sns_topic.my_event_subscription_topic.arn
protocol = "lambda"
endpoint = aws_lambda_function.my_lambda_function.arn
}
resource "aws_sns_topic_policy" "allow_publish" {
arn = aws_sns_topic.my_event_subscription_topic.arn
policy = data.aws_iam_policy_document.allow_dms_and_events_document.json
}
resource "aws_lambda_permission" "allow_sns_invoke" {
statement_id = "AllowExecutionFromSNS"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.my_lambda_function.function_name
principal = "sns.amazonaws.com"
source_arn = aws_sns_topic.my_event_subscription_topic.arn
}
data "aws_iam_policy_document" "allow_dms_and_events_document" {
statement {
actions = ["SNS:Publish"]
principals {
identifiers = [
"dms.amazonaws.com",
"events.amazonaws.com"
]
type = "Service"
}
resources = [aws_sns_topic.my_event_subscription_topic.arn]
}
}
Am I missing something?
Is event_categories = ["state change"] correct? (This suggests state change is correct.
I'm less concerned right now if the Lambda is triggered for every state change, and not just DMS-EVENT-0079.)
Is there something I can add to get CloudWatch logs from the event subscription, to tell me what's wrong?
You can try giving it a JSON as shared on AWS Documentation.
{
"version":"0",
"id":"11a11b11-222b-333a-44d4-01234a5b67890",
"detail-type":"DMS Replication Task State Change",
"source":"aws.dms",
"account":"0123456789012",
"time":"1970-01-01T00:00:00Z",
"region":"us-east-1",
"resources":[
"arn:aws:dms:us-east-1:012345678901:task:AAAABBBB0CCCCDDDDEEEEE1FFFF2GGG3FFFFFF3"
],
"detail":{
"type":"ReplicationTask",
"category":"StateChange",
"eventType":"REPLICATION_TASK_STARTED",
"eventName":"DMS-EVENT-0069",
"resourceLink":"https://console.aws.amazon.com/dms/v2/home?region=us-east-1#taskDetails/taskName",
"detailMessage":"Replication task started, with flag = fresh start"
}
}
You can check how to give this as JSON in Terraform here

Issue with AWS Lambda Provisioned Concurrency using Terraform

I have been trying to configure Provisioned Concurrency for my AWS Lambda function. I have been hitting ValidationException again and again. I tried qualifier attribute for both alias version and alias name. While terraform apply it waits for 2 mins and throws the error but it is configured successfully in AWS console with status ready. Below is my configuration.
resource "aws_lambda_alias" "contact_lambda_alias" {
name = module.aws_lambda_function_contact_alias_label.id
function_name = module.terraform_aws_lambda_contact.lambda_arn
function_version = module.terraform_aws_lambda_contact.latest_published_version
}
resource "aws_lambda_provisioned_concurrency_config" "contact_lambda_alias" {
function_name = module.terraform_aws_lambda_contact.lambda_arn
provisioned_concurrent_executions = 1
qualifier = module.terraform_aws_lambda_contact.latest_published_version
timeouts {
create = "30m"
update = "30m"
}
}
I tried with and without timeouts block but still hitting the ValidationException again and again .
This is the error
ValidationException
You should be using alias arn:
function_name = aws_lambda_alias.contact_lambda_alias.arn

Why does this AWS Lambda function keep looping from this EventBridge rule for AWS ECS?

I have an EventBridge rule where it invokes a Lambda function (target) when one of the ECS Tasks starts (status: RUNNING). The Lambda function does something then at the end it is supposed to stop the ECS Task.
I have the following EventBridge rule:
{
"source": ["aws.ecs"],
"detail-type": ["ECS Task State Change"],
"detail": {
"clusterArn": ["<cluster-arn>"],
"lastStatus": ["RUNNING"],
"desiredStatus": ["RUNNING"]
}
}
And it invokes the Lambda function.
The following is a simplified version of the Lambda function:
import { ECSClient, StopTaskCommand } from "#aws-sdk/client-ecs";
export const handler = async (event, context, callback) => {
// event has the EventBridge event capture from the AWS ECS Task
// Do something
const ecs = new ECSClient({ region: "<region>" })
var taskArn = event.detail.containers[0].taskArn;
var stopTask = new StopTaskCommand({
cluster: "<cluster-arn>",
reason: "<reason>",
task: taskArn
});
try {
const data = await ecs.send(stopTask);
} catch (error) {
console.log(error)
}
}
When I start the ECS Task, the Lambda function is invoked and starts to run. After it finishes what it is supposed to do, it then goes to stop the ECS Task which invoked it. I use the aws-sdk v3 for this where I get the taskArn from the event parameter of the Lambda function. The Lambda function can successfully stop the ECS Task (I receive a 200 HTTP response code from result of the send command). However, the Lambda function is then invoked again and it repeats this forever (I checked the CloudWatch logs for the function).
I am not sure why the Lambda function starts up again as, from what I can tell, the EventBridge rule shouldn't trigger it.
Is not a problem with your Lambda Function. Is the desired behavior of your ECS Service!
Your ECS Service has a property "desired count", which instructs the service to meet the desired state.
If your service indicates that it should have 1 replica, then if you kill the task, the service will try to launch a new one until it meets the desired quantity. For this reason you are seeing that it returns to have activity over and over again.
It is probably not the correct approach to kill the service.
What I would do is change the "desired count" to zero, without using the lambda function.

AWS lambda missing events from dynamodb stream

I am consistently missing lambda triggers from a dynamodb stream. I am mapping the dynamodb stream to the lambda function with event_source_mapping resource.
resource "aws_lambda_event_source_mapping" "history" {
event_source_arn = "${data.aws_dynamodb_table.auditlogDynamoDB.stream_arn}"
function_name = "${module.cx-clientcomm-history-lambda.lambda_function_arn}"
starting_position = "LATEST"
maximum_retry_attempts = 0
maximum_record_age_in_seconds = 604800 // adding to explicitly set. QA plan was providing invalid value
#(Optional) An Amazon SQS queue or Amazon SNS topic destination for failed records.
destination_config {
on_failure {
destination_arn = "${data.aws_sns_topic.cx-clientcomm-sns-slack.arn}"
}
}
}
It appears when there are entries in dynamodb are coming it very close to each other, some are not picked up by the event_source_mapping and not sent to the lambda.
Is there a way to make sure this doesn't happen? This needs to be very reliable

Terraform: CloudWatch Event that notifies SNS

I'm learning TF and trying to apply an infrastructure that creates:
a simple lambda function
an SNS topic
get that lambda to subscribe the SNS topic
a Cloud Watch Event that publishes a message to the topic at some interval
a Cloud Watch Log Group to check if the lambda gets notified by the SNS
The lambda permission to allow calls from SNS
I'm able to apply that successfully. The infrastructure seems perfectly fine (it has the same aspect when I create that myself through the visual aws console)
But the cloud watch Event doesn't get triggered (when built from TF), so no message is published to SNS and lambda doesn't get called. I don't know why
Anyone know how can I accomplish that? Bellow my .tf script:
provider "aws" {
region = "us-east-1"
}
//lambda function handler & code file
resource "aws_lambda_function" "lambda-function" {
function_name = "Function01"
handler = "com.rafael.lambda.Function01"
role = "arn:aws:iam::12345:role/LambdaRoleTest"
runtime = "java8"
s3_bucket = aws_s3_bucket.sns-test.id
s3_key = aws_s3_bucket_object.file_upload.id
source_code_hash = filebase64sha256("../target/sns-cw-lambda-poc.jar")
}
//allow sns to call lambda
resource "aws_lambda_permission" "allow-sns-to-lambda" {
function_name = aws_lambda_function.lambda-function.function_name
action = "lambda:InvokeFunction"
principal = "sns.amazonaws.com"
source_arn = aws_sns_topic.call-lambdas-topic.arn
statement_id = "AllowExecutionFromSNS"
}
//app s3 repository
resource "aws_s3_bucket" "sns-test" {
bucket = "app-bucket-12345"
region = "us-east-1"
}
//app jar file
resource "aws_s3_bucket_object" "file_upload" {
depends_on = [
aws_s3_bucket.sns-test
]
bucket = aws_s3_bucket.sns-test.id
key = "sns-cw-lambda-poc.jar"
source = "../target/sns-cw-lambda-poc.jar"
server_side_encryption = "AES256"
etag = filebase64sha256("../target/sns-cw-lambda-poc.jar")
}
//to check lambda exec logs
resource "aws_cloudwatch_log_group" "lambda-cloudwatch-logs" {
name = "/aws/lambda/${aws_lambda_function.lambda-function.function_name}"
retention_in_days = 1
}
//rule to trigger SNS
resource "aws_cloudwatch_event_rule" "publish-sns-rule" {
name = "publish-sns-rule"
schedule_expression = "rate(1 minute)"
}
//cloud watch event targets SNS
resource "aws_cloudwatch_event_target" "sns-publish" {
count = "1"
rule = aws_cloudwatch_event_rule.publish-sns-rule.name
target_id = aws_sns_topic.call-lambdas-topic.name
arn = aws_sns_topic.call-lambdas-topic.arn
}
//SNS topic to subscribe
resource "aws_sns_topic" "call-lambdas-topic" {
name = "call-lambdas-topic"
}
//lambda subscribes the topic, so it should be nofied when other resource publishes to the topic
resource "aws_sns_topic_subscription" "sns-lambda-subscritption" {
topic_arn = aws_sns_topic.call-lambdas-topic.arn
protocol = "lambda"
endpoint = aws_lambda_function.lambda-function.arn
}
I figured it out, I forgot to add the SNS policies that allow CloudWatch to publish to SNS topic. To get the above script to work, just add this:
resource "aws_sns_topic_policy" "default" {
count = 1
arn = aws_sns_topic.call-lambdas-topic.arn
policy = "${data.aws_iam_policy_document.sns_topic_policy.0.json}"
}
data "aws_iam_policy_document" "sns_topic_policy" {
count = "1"
statement {
sid = "Allow CloudwatchEvents"
actions = ["sns:Publish"]
resources = [aws_sns_topic.call-lambdas-topic.arn]
principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}
}
}

Resources