I am taking inspiration from this AWS post to start and stop RDS automatically based on a schedule. Instead of using event trigger, i am using event scheduler as you can pass timezone with the cron expression. I see that my event is getting created, but it is not invoking the target lambda. Not able to debug why.
Relevant Code:
Event Bridge:
resource "aws_scheduler_schedule" "lambda-trigger-rule" {
description = "Eventbridge schedule to trigger lambda that stops/starts RDS"
flexible_time_window {
mode = "OFF"
}
schedule_expression = var.schedule_expression
schedule_expression_timezone = "Europe/Amsterdam"
target {
arn = var.lambda_function_arn
role_arn = var.iam_role_arn
}
}
Lambda:
locals {
name = var.rds_shutdown ? "rds-shutdown" : "rds-start"
lambda_output_path_dir = var.rds_shutdown ? "/tmp/tfartifacts_stp" : "/tmp/tfartifacts_strt"
}
data "aws_region" "current" {}
resource "null_resource" "install_dependencies" {
provisioner "local-exec" {
command = "mkdir -p ${local.lambda_output_path_dir} && cp -r ${path.module}/python/${local.name} ${local.lambda_output_path_dir}/python"
}
triggers = {
always_run = timestamp()
}
}
data "archive_file" "zip_the_python_code" {
type = "zip"
source_dir = "${local.lambda_output_path_dir}/python"
output_path = "${local.lambda_output_path_dir}/${local.name}.zip"
depends_on = [null_resource.install_dependencies]
}
resource "aws_lambda_function" "this" {
filename = data.archive_file.zip_the_python_code.output_path
source_code_hash = data.archive_file.zip_the_python_code.output_base64sha256
function_name = local.name
role = var.lambda_stop_start_role_arn
handler = "lambda_function.lambda_handler"
runtime = "python3.9"
timeout = 180
vpc_config {
subnet_ids = var.subnet_ids
security_group_ids = var.security_group_ids
}
environment {
variables = {
"REGION" = data.aws_region.current.name
"KEY" = "Auto-Start-Shutdown"
"VALUE" = true
}
}
}
IAM Role:
resource "aws_iam_role" "scheduler_role" {
name = "scheduler_role_to_trigger_lambda"
permissions_boundary = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/AdministratorAccessPermissionBoundary"
assume_role_policy = jsonencode({
"Version" = "2012-10-17"
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "scheduler.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
})
}
resource "aws_iam_policy" "lambda_invoke_policy" {
name = "lambda_invoke_policy"
description = "Permissions required by scheduler to invoke lambda function"
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : [
"lambda:Invoke"
],
"Effect" : "Allow",
"Resource" : "*"
}
]
})
}
resource "aws_iam_role_policy_attachment" "scheduler_lambda_invoke_policy_attachment" {
role = aws_iam_role.scheduler_role.name
policy_arn = aws_iam_policy.lambda_invoke_policy.arn
}
But as seen here: , event got scheduled at right time but it never invoked the lambda. How to fix this?
This is not exactly the response you are looking for, but I think it is worth mentioning. You don't need a Lambda function to start and stop an RDS instance. You can do it directly from EventBridge like this:
resource "aws_scheduler_schedule" "lambda-trigger-rule" {
description = "Eventbridge schedule to trigger lambda that stops/starts RDS"
flexible_time_window {
mode = "OFF"
}
schedule_expression = var.schedule_expression
schedule_expression_timezone = "Europe/Amsterdam"
target {
arn = "arn:aws:scheduler:::aws-sdk:rds:stopDBInstance"
role_arn = var.iam_role_arn
input = jsonencode({
DbInstanceIdentifier = var.rds_instance_identifier // here goes the instance identifier
})
}
}
You can find the complete code, including one to stop EC2 instances, here: https://github.com/andresmiguel/aws-lambda-rds/blob/main/terraform/environment/saver-bot/schedules.tf