/** * # SecretRotationReminder * Deploy lambda function which takes secret rotation event from secretsmanager * and send reminders to users using SNS. * This function can be used by any number of secrets * Secret ARN is obtained from the secretsmanager event * * This function overrides the blueprint function from AWS. Instead of rotating the secret value, * it sends a reminder to user who will manually rotate the secret. */ resource "aws_sns_topic" "reminder" { name = "${var.prefix}-SecretRotationReminder" kms_master_key_id = var.sns-cmk-arn } resource "aws_sns_topic_subscription" "reminder" { for_each = toset(var.rotation-reminder-recipients) topic_arn = aws_sns_topic.reminder.arn protocol = "email" endpoint = each.value } data "archive_file" "payload" { type = "zip" source_file = "${path.module}/rotation_reminder.py" output_path = "payload.zip" } data "aws_subnet" "this" { id = var.lambda-subnet-ids[0] } resource "aws_security_group" "rotation-reminder" { name = "${var.prefix}-SecretRotationReminder" description = "Allow access to VPC endpoint" vpc_id = data.aws_subnet.this.vpc_id egress { description = "Access to VPC endpoints" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_lambda_function" "rotation-reminder" { function_name = "${var.prefix}-SecretRotationReminder" description = "Sends secret rotation reminder" role = aws_iam_role.lambda.arn handler = "rotation_reminder.lambda_handler" filename = data.archive_file.payload.output_path source_code_hash = data.archive_file.payload.output_base64sha256 runtime = "python3.13" timeout = 180 vpc_config { subnet_ids = var.lambda-subnet-ids security_group_ids = [aws_security_group.rotation-reminder.id] } environment { variables = { SNS_TOPIC_ARN = aws_sns_topic.reminder.arn } } } resource "aws_lambda_permission" "rotation-reminder" { statement_id = "SecretRotationReminderPermission" action = "lambda:InvokeFunction" function_name = aws_lambda_function.rotation-reminder.function_name principal = "secretsmanager.amazonaws.com" # this function should be allowed to send reminders for all secrets # source_arn = module.mock-secret.secret_arn } resource "aws_cloudwatch_log_group" "rotation-reminder" { name = "/aws/lambda/whk1-bea-icc-obk-SecretRotationReminder" retention_in_days = 400 # intentionally set to longer than 1 year as rotation may happen yearly kms_key_id = var.logs-cmk-arn } resource "aws_iam_role" "lambda" { name = "${var.prefix}-SecretRotationReminderFunctionRole" assume_role_policy = data.aws_iam_policy_document.assume_role.json } resource "aws_iam_role_policy_attachment" "lambda" { for_each = { for k, v in [ "arn:aws:iam::aws:policy/AWSLambdaExecute", aws_iam_policy.lambda.arn ] : k => v } role = aws_iam_role.lambda.name policy_arn = each.value } resource "aws_iam_policy" "lambda" { name_prefix = "SecretRotationPolicy" policy = jsonencode( { "Version" : "2012-10-17", "Statement" : [ { "Sid" : "AllowAccessToSecretSnsVpc", "Effect" : "Allow", "Action" : [ "SNS:Publish", "secretsmanager:DescribeSecret", "secretsmanager:ListSecretVersionIds", "secretsmanager:UpdateSecretVersionStage", "secretsmanager:GetSecretValue", "secretsmanager:PutSecretValue", "ec2:CreateNetworkInterface", "ec2:DescribeNetworkInterfaces", "ec2:DescribeSubnets", "ec2:DeleteNetworkInterface", "ec2:AssignPrivateIpAddresses", "ec2:UnassignPrivateIpAddresses", "ec2:DescribeSecurityGroups", "ec2:DescribeSubnets", "ec2:DescribeVpcs", "ec2:GetSecurityGroupsForVpc" ], "Resource" : "*" } ] } ) } data "aws_iam_policy_document" "assume_role" { statement { effect = "Allow" principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } actions = ["sts:AssumeRole"] } }