Terraform-provider-aws: Cloudwatch Event trigger Lambda doesn't associate unless we do a manual update to cloudwatch event.

Created on 13 Jun 2017  ·  11Comments  ·  Source: hashicorp/terraform-provider-aws

_This issue was originally opened by @sandyfox as hashicorp/terraform#14342. It was migrated here as part of the provider split. The original body of the issue is below._


Hi there,

Terraform Launches all the required resources as expected. But the Event trigger is not being associated with the lambda function. Had to update the cloudwatch event manually from the console to add it as a trigger to lambda and to invoke.

Terraform Version

Terraform v0.9.4

Affected Resource(s)

AWS Lambda
AWS Cloudwatch Event rule/target

Expected Behavior

Under lambda function triggers tab you should see the "CloudWatch Events - Schedule:*" and should be invoked by the Cloudwatch event as per the Schedule expression.

Actual Behavior

What actually happened?

Terraform Launches all the required resources as expected. But the Event trigger is not being associated with the lambda function. Had to update the cloudwatch event manually from the console to add it as a trigger to lambda and to invoke.

Steps to Reproduce

We can reproduce by running below resources by providing some meaningful zip to the function.

resource "aws_lambda_function" "waf_spam_list" {
filename = "lambda.zip"
function_name = "waf_spam_list"
role = "arn:aws:iam::xxxxxxxxxxxx:role/xxxxxxxxxxxxx"
handler = "index.handler"
source_code_hash = "${base64sha256(file("lambda.zip"))}"
runtime = "nodejs4.3"
timeout = "59"
}

resource "aws_cloudwatch_event_rule" "waf-spam-update" {
name = "waf-spam-update"
depends_on = ["aws_lambda_function.waf_spam_list"]
schedule_expression = "rate(1 minute)"
}

resource "aws_cloudwatch_event_target" "waf-spam-target" {
target_id = "waf-spam-target"
rule = "${aws_cloudwatch_event_rule.waf-spam-update.name}"
arn = "${aws_lambda_function.waf_spam_list.arn}"
input = < { some json input }
INPUT
}

bug serviccloudwatchevents serviclambda

Most helpful comment

@tobstarr I was having the same problem and I took your suggestion and ultimately here is the code that worked for me in its entirety (minus the iam_role and iam_role_policy):

NOTE: I added target_id and depends_on and that was what worked for me. Not sure which of those I needed. Haven't gone through a process of elimination to see which one is necessary and I'm a novice at terraform so can't say without further experimentation.

data "archive_file" "function" {
  type = "zip"
  source_file = "${path.module}/index.js"
  output_path = "${path.module}/function.zip"
}

resource "aws_lambda_function" "demo_lambda" {
  function_name = "demo_lambda"
  handler = "index.handler"
  runtime = "nodejs6.10"
  filename = "function.zip"
  source_code_hash = "${base64sha256(file("function.zip"))}"
  role = "${aws_iam_role.lambda_exec_role.arn}"
}

resource "aws_cloudwatch_event_rule" "demo_lambda_every_one_minute" {
  name = "demo_lambda_every_one_minute"
  // Worked for me after I added `depends_on`
  depends_on = [
    "aws_lambda_function.demo_lambda"
  ]
  schedule_expression = "rate(1 minute)"
}

resource "aws_cloudwatch_event_target" "demo_lambda" {
  target_id = "demo_lambda" // Worked for me after I added `target_id`
  rule = "${aws_cloudwatch_event_rule.demo_lambda_every_one_minute.name}"
  arn = "${aws_lambda_function.demo_lambda.arn}"
}

resource "aws_lambda_permission" "demo_lambda_every_one_minute" {
  statement_id = "AllowExecutionFromCloudWatch"
  action = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.demo_lambda.function_name}"
  principal = "events.amazonaws.com"
  source_arn = "${aws_cloudwatch_event_rule.demo_lambda_every_one_minute.arn}"
}

CC: https://github.com/hashicorp/terraform/issues/14342

All 11 comments

I am having the same issue. It is extremely frustrating

@jackmandelkorn looks like you also need to allow cloudwatch to invoke those lambda functions. This is what seemed to have worked for me:

resource "aws_lambda_permission" "<function_name>" {
  statement_id   = "AllowExecutionFromCloudWatch"
  action         = "lambda:InvokeFunction"
  function_name  = "<function_name>"
  principal      = "events.amazonaws.com"
  source_account = "${data.aws_caller_identity.current.account_id}"
  source_arn     = "${aws_cloudwatch_event_rule.1h.arn}"
}

I wonder if there is a more convenient way to do this. After the permissions are set the trigger also shows up in the lambda console.

@tobstarr I was having the same problem and I took your suggestion and ultimately here is the code that worked for me in its entirety (minus the iam_role and iam_role_policy):

NOTE: I added target_id and depends_on and that was what worked for me. Not sure which of those I needed. Haven't gone through a process of elimination to see which one is necessary and I'm a novice at terraform so can't say without further experimentation.

data "archive_file" "function" {
  type = "zip"
  source_file = "${path.module}/index.js"
  output_path = "${path.module}/function.zip"
}

resource "aws_lambda_function" "demo_lambda" {
  function_name = "demo_lambda"
  handler = "index.handler"
  runtime = "nodejs6.10"
  filename = "function.zip"
  source_code_hash = "${base64sha256(file("function.zip"))}"
  role = "${aws_iam_role.lambda_exec_role.arn}"
}

resource "aws_cloudwatch_event_rule" "demo_lambda_every_one_minute" {
  name = "demo_lambda_every_one_minute"
  // Worked for me after I added `depends_on`
  depends_on = [
    "aws_lambda_function.demo_lambda"
  ]
  schedule_expression = "rate(1 minute)"
}

resource "aws_cloudwatch_event_target" "demo_lambda" {
  target_id = "demo_lambda" // Worked for me after I added `target_id`
  rule = "${aws_cloudwatch_event_rule.demo_lambda_every_one_minute.name}"
  arn = "${aws_lambda_function.demo_lambda.arn}"
}

resource "aws_lambda_permission" "demo_lambda_every_one_minute" {
  statement_id = "AllowExecutionFromCloudWatch"
  action = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.demo_lambda.function_name}"
  principal = "events.amazonaws.com"
  source_arn = "${aws_cloudwatch_event_rule.demo_lambda_every_one_minute.arn}"
}

CC: https://github.com/hashicorp/terraform/issues/14342

I've run into the exact same thing, and @snasirca fix worked for me.

resource "aws_lambda_permission" "demo_lambda_every_one_minute" {
  statement_id = "AllowExecutionFromCloudWatch"
  action = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.demo_lambda.function_name}"
  principal = "events.amazonaws.com"
  source_arn = "${aws_cloudwatch_event_rule.demo_lambda_every_one_minute.arn}"
}

this part does the trick. I dont need additions on aws_cloudwatch_event_rule and aws_cloudwatch_event_target

I found my way here for a different bug. In the end the solution was slightly different below are the relevant pieces:
broken:

resource "aws_lambda_function" "lambda" {
  function_name    = "${var.function_name}"
  filename         = "${var.lambda_zip}"
  timeout          = "${var.lambda_timeout}"
  role             = "${aws_iam_role.lambda.arn}"
  handler          = "process_controller.lambda_handler"
  source_code_hash = "${base64sha256(file("${path.module}/src/process_controller.py"))}"
  runtime          = "python3.6"

  dead_letter_config {
    target_arn = "${aws_sns_topic.dead_letter.arn}"
  }
}

resource "aws_lambda_permission" "allow_cloudwatch" {
  statement_id   = "AllowExecutionFromCloudWatch"
  action         = "lambda:InvokeFunction"
  function_name  = "${aws_lambda_function.lambda.function_name}"
  principal      = "events.amazonaws.com"
  source_account = "${local.account_id}"
  source_arn     = "${aws_cloudwatch_event_rule.codedeploy.arn}"
}

resource "aws_cloudwatch_event_rule" "codedeploy" {
  depends_on  = ["aws_lambda_function.lambda"]
  name        = "${aws_lambda_function.lambda.function_name}-event-rule"
  description = "Capture START STOP FAILURE SUCCESS and toggle ASG Processes"

  event_pattern = <<PATTERN
{
  "source": [
    "aws.codedeploy"
  ],
  "detail-type": [
    "CodeDeploy Deployment State-change Notification"
  ],
  "detail": {
    "application": [
      "${var.app_name}"
    ]
  }
}
PATTERN
}

resource "aws_cloudwatch_event_target" "lambda" {
  rule      = "${aws_cloudwatch_event_rule.codedeploy.name}"
  target_id = "LambdaAsgProcManager"
  arn       = "${aws_lambda_function.lambda.arn}"
}

Working version - notice the permission drops source account_id. For this type of rule Source Account ID is not a valid parameter. I have not tested if AWS SDK returns an error here or not; but AWS Support provided me this information. I could not find an error message so far.

resource "aws_lambda_function" "lambda" {
  function_name    = "${var.function_name}"
  filename         = "${var.lambda_zip}"
  timeout          = "${var.lambda_timeout}"
  role             = "${aws_iam_role.lambda.arn}"
  handler          = "process_controller.lambda_handler"
  source_code_hash = "${base64sha256(file("${path.module}/src/process_controller.py"))}"
  runtime          = "python3.6"

  dead_letter_config {
    target_arn = "${aws_sns_topic.dead_letter.arn}"
  }
}

resource "aws_lambda_permission" "allow_cloudwatch" {
  statement_id  = "AllowExecutionFromCloudWatch"
  action        = "lambda:InvokeFunction"
  function_name = "${aws_lambda_function.lambda.function_name}"
  principal     = "events.amazonaws.com"
  source_arn    = "${aws_cloudwatch_event_rule.codedeploy.arn}"
}

resource "aws_cloudwatch_event_rule" "codedeploy" {
  depends_on  = ["aws_lambda_function.lambda"]
  name        = "${aws_lambda_function.lambda.function_name}-event-rule"
  description = "Capture START STOP FAILURE SUCCESS and toggle ASG Processes"

  event_pattern = <<PATTERN
{
  "source": [
    "aws.codedeploy"
  ],
  "detail-type": [
    "CodeDeploy Deployment State-change Notification"
  ],
  "detail": {
    "application": [
      "${var.app_name}"
    ]
  }
}
PATTERN
}

resource "aws_cloudwatch_event_target" "lambda" {
  rule      = "${aws_cloudwatch_event_rule.codedeploy.name}"
  target_id = "LambdaAsgProcManager"
  arn       = "${aws_lambda_function.lambda.arn}"
}

I'm not sure if we want to separate out this bug (which may or may not be fix-able depending on SDK error messages), from a documentation update about depends_on?

Tried different proposed fixes. I can confirm that providing source_arn = "${aws_cloudwatch_event_rule.example_event_rule.arn}" to the _aws_lambda_permission_ worked well.

Maybe we should update the docs to mark this attribute as Required instead of being optional? Not sure if this is in conformity to the AWS SDK, but if Terraform requires this, it really is required, yet.

I'm hitting this bug as well (Terraform v0.11.10
I can't use depends-on since it doesn't support interpolations. since this code run inside a module calling another module

Having this problem with Terraform v0.11.11. Using depends_on and target_id as mentioned above does not work for me

Hi folks 👋 This looks like it was answered above with using the aws_lambda_permission resource. There is already a note included in the aws_cloudwatch_event_target resource documentation:

Note: In order to be able to have your AWS Lambda function or SNS topic invoked by a CloudWatch Events rule, you must setup the right permissions using aws_lambda_permission or aws_sns_topic.policy. More info here.

If you have further suggestions for improvements to the documentation, please create a new GitHub issue or submit changes to the resource documentation files (e.g. website/docs/r/cloudwatch_event_target.html.markdown). 👍

I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

Was this page helpful?
0 / 5 - 0 ratings