Lambda Magic for RDS

Steps below to create:

To stop an RDS instance every 7 days using AWS Lambda and Terraform, below are the following concepts followed:

Explanation:

  • Step 1
  • Step 2
    • Lambda FunctionA Python-based Lambda function that uses the AWS SDK (boto3) to stop the specified RDS instance(s).
  • Step 3
  • Step 4
    • To deploy:
      • Save the Terraform code in .tf files and the Python code as lambda_function.py.
      • Zip the Python file into lambda_function.zip.
      • Initialize Terraform: terraform init
      • Plan the deployment: terraform plan
        • Apply the changes: terraform apply
  • Main.tf
# Define an IAM role for the Lambda function
resource "aws_iam_role" "rds_stop_lambda_role" {
  name = "rds-stop-lambda-role"

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

# Attach a policy to the role allowing RDS stop actions and CloudWatch Logs
resource "aws_iam_role_policy" "rds_stop_lambda_policy" {
  name = "rds-stop-lambda-policy"
  role = aws_iam_role.rds_stop_lambda_role.id

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "rds:StopDBInstance",
          "rds:DescribeDBInstances"
        ],
        Resource = "*" # Restrict this to specific RDS instances if needed
      },
      {
        Effect = "Allow",
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ],
        Resource = "arn:aws:logs:*:*:*"
      }
    ]
  })
}

# Create the Lambda function
resource "aws_lambda_function" "rds_stop_lambda" {
  function_name = "rds-stop-every-7-days"
  handler       = "lambda_function.lambda_handler"
  runtime       = "python3.9"
  role          = aws_iam_role.rds_stop_lambda_role.arn
  timeout       = 60

  # Replace with the path to your zipped Lambda code
  filename         = "lambda_function.zip"
  source_code_hash = filebase64sha256("lambda_function.zip")

  environment {
    variables = {
      RDS_INSTANCE_IDENTIFIER = "my-rds-instance" # Replace with your RDS instance identifier
      REGION                  = "us-east-1"       # Replace with your AWS region
    }
  }
}

# Create an EventBridge (CloudWatch Event) rule to trigger the Lambda
resource "aws_cloudwatch_event_rule" "rds_stop_schedule" {
  name                = "rds-stop-every-7-days-schedule"
  schedule_expression = "cron(0 0 ? * SUN *)" # Every Sunday at 00:00 UTC
}

# Add the Lambda function as a target for the EventBridge rule
resource "aws_cloudwatch_event_target" "rds_stop_target" {
  rule      = aws_cloudwatch_event_rule.rds_stop_schedule.name
  target_id = "rds-stop-lambda-target"
  arn       = aws_lambda_function.rds_stop_lambda.arn
}

# Grant EventBridge permission to invoke the Lambda function
resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda" {
  statement_id  = "AllowExecutionFromCloudWatch"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.rds_stop_lambda.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.rds_stop_schedule.arn
}
  • lambda_function.py (Python code for the Lambda function):
import boto3
import os

def lambda_handler(event, context):
    rds_instance_identifier = os.environ.get('RDS_INSTANCE_IDENTIFIER')
    region = os.environ.get('REGION')

    if not rds_instance_identifier or not region:
        print("Error: RDS_INSTANCE_IDENTIFIER or REGION environment variables are not set.")
        return {
            'statusCode': 400,
            'body': 'Missing environment variables.'
        }

    rds_client = boto3.client('rds', region_name=region)

    try:
        response = rds_client.stop_db_instance(
            DBInstanceIdentifier=rds_instance_identifier
        )
        print(f"Successfully initiated stop for RDS instance: {rds_instance_identifier}")
        return {
            'statusCode': 200,
            'body': f"Stopping RDS instance: {rds_instance_identifier}"
        }
    except Exception as e:
        print(f"Error stopping RDS instance {rds_instance_identifier}: {e}")
        return {
            'statusCode': 500,
            'body': f"Error stopping RDS instance: {e}"
        }
  • Zipping the Lambda Code:
zip lambda_function.zip lambda_function.py

Leave a comment