From 16ec64a7e9921c2b3e74f4121afc47fcf2580d82 Mon Sep 17 00:00:00 2001 From: Renato Date: Wed, 21 Aug 2024 00:54:30 +1000 Subject: [PATCH 1/5] fix default behaviour when not aws_sns_topic does not exist --- _variables.tf | 2 +- alarms.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_variables.tf b/_variables.tf index ebfb11f..78e4268 100644 --- a/_variables.tf +++ b/_variables.tf @@ -21,7 +21,7 @@ variable "sns_topic_name" { default = "CISAlarmV2" } -variable "chatbot_sns_topic" { +variable "alarm_notification_sns_topic" { description = "The arn of the SNS Topic which will be notified when any alarm is performed." type = string default = "" diff --git a/alarms.tf b/alarms.tf index 1a1bd8b..e10040d 100644 --- a/alarms.tf +++ b/alarms.tf @@ -13,6 +13,6 @@ resource "aws_cloudformation_stack" "cloudtrail_alarm" { parameters = { CloudTrailLogGroupName = var.cloudtrail_log_group_name - AlarmNotificationTopic = var.chatbot_sns_topic + AlarmNotificationTopic = try(aws_sns_topic.alarms[0].arn, var.alarm_notification_sns_topic) } } From 585ef5105a4cb4922cab1c8ed67316d0bde43409 Mon Sep 17 00:00:00 2001 From: Renato Date: Wed, 21 Aug 2024 01:40:33 +1000 Subject: [PATCH 2/5] enable generic msg back to sns --- _variables.tf | 7 +++++-- event_bridge.tf | 6 +++--- iam.tf | 8 ++++---- main.tf | 7 ++++--- sns.tf | 10 +++++----- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/_variables.tf b/_variables.tf index 78e4268..5b5f4cb 100644 --- a/_variables.tf +++ b/_variables.tf @@ -27,11 +27,14 @@ variable "alarm_notification_sns_topic" { default = "" } -variable "emails" { +variable "endpoints" { default = [] type = list(string) } - +variable "alarm_protocol" { + default = "email" + type = string +} variable "alarm_mode" { default = "light" type = string diff --git a/event_bridge.tf b/event_bridge.tf index 170da31..693421c 100644 --- a/event_bridge.tf +++ b/event_bridge.tf @@ -1,5 +1,5 @@ resource "aws_cloudwatch_event_rule" "alarm_notification" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail_alarm_custom_notifications" description = "Will be notified with a custom message when any alarm is performed" @@ -23,8 +23,8 @@ resource "aws_cloudwatch_event_rule" "alarm_notification" { } resource "aws_cloudwatch_event_target" "lambda_target" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 rule = aws_cloudwatch_event_rule.alarm_notification[0].name target_id = "NotifyLambda" - arn = aws_lambda_function.lambda[0].arn + arn = var.alarm_protocol == "email" ? aws_lambda_function.lambda[0].arn : aws_sns_topic.alarms[0].arn } diff --git a/iam.tf b/iam.tf index 16ef74b..f572747 100644 --- a/iam.tf +++ b/iam.tf @@ -1,5 +1,5 @@ data "aws_iam_policy_document" "lambda_assume_role" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 statement { actions = ["sts:AssumeRole"] principals { @@ -10,14 +10,14 @@ data "aws_iam_policy_document" "lambda_assume_role" { } resource "aws_iam_role" "iam_for_lambda" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-role-${data.aws_region.current.name}" assume_role_policy = data.aws_iam_policy_document.lambda_assume_role[0].json tags = var.tags } resource "aws_iam_policy" "lambda_cw" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-policy-${data.aws_region.current.name}" path = "/" description = "IAM policy for logging from a lambda" @@ -53,7 +53,7 @@ resource "aws_iam_policy" "lambda_cw" { } resource "aws_iam_role_policy_attachment" "lambda_cw" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 role = aws_iam_role.iam_for_lambda[0].name policy_arn = aws_iam_policy.lambda_cw[0].arn } diff --git a/main.tf b/main.tf index a824140..ef906b7 100644 --- a/main.tf +++ b/main.tf @@ -1,5 +1,5 @@ resource "aws_lambda_function" "lambda" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 filename = "${path.module}/lambda.zip" function_name = var.lambda_name role = aws_iam_role.iam_for_lambda[0].arn @@ -21,7 +21,7 @@ resource "aws_lambda_function" "lambda" { } resource "aws_lambda_permission" "default" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 statement_id = "AllowExecutionFromEventBridge" action = "lambda:InvokeFunction" function_name = aws_lambda_function.lambda[0].function_name @@ -30,8 +30,9 @@ resource "aws_lambda_permission" "default" { } resource "aws_cloudwatch_log_group" "alarm_lambda" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "/aws/lambda/${var.lambda_name}" retention_in_days = 365 + kms_key_id = var.kms_key tags = var.tags } diff --git a/sns.tf b/sns.tf index 0ddad30..cf81d6f 100644 --- a/sns.tf +++ b/sns.tf @@ -2,7 +2,7 @@ # The SNS topic to which CloudWatch alarms send events. # -------------------------------------------------------------------------------------------------- resource "aws_sns_topic" "alarms" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = var.sns_topic_name kms_master_key_id = var.kms_key #aws_kms_key.sns[0].id # default key does not allow cloudwatch alarms to publish tags = var.tags @@ -10,13 +10,13 @@ resource "aws_sns_topic" "alarms" { resource "aws_sns_topic_policy" "alarms" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 arn = aws_sns_topic.alarms[0].arn policy = data.aws_iam_policy_document.alarms_policy[0].json } data "aws_iam_policy_document" "alarms_policy" { - count = length(var.emails) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 policy_id = "allow-org-accounts" statement { @@ -46,8 +46,8 @@ data "aws_iam_policy_document" "alarms_policy" { } resource "aws_sns_topic_subscription" "cloudtrail_custom_alarm_email" { - for_each = toset(var.emails) + for_each = toset(var.endpoints) topic_arn = aws_sns_topic.alarms[0].arn - protocol = "email" + protocol = var.alarm_protocol endpoint = each.value } From 73931b4c35743453b2d3d26a4d2e837b01b299f8 Mon Sep 17 00:00:00 2001 From: Renato Date: Wed, 21 Aug 2024 10:18:01 +1000 Subject: [PATCH 3/5] ensure only email protocol use custom lambda --- alarms.tf => aws-alarms.tf | 2 +- event_bridge.tf => aws-event_bridge.tf | 2 +- iam.tf => aws-iam.tf | 8 ++++---- main.tf => aws-lambda.tf | 6 +++--- sns.tf => aws-sns.tf | 0 5 files changed, 9 insertions(+), 9 deletions(-) rename alarms.tf => aws-alarms.tf (77%) rename event_bridge.tf => aws-event_bridge.tf (94%) rename iam.tf => aws-iam.tf (82%) rename main.tf => aws-lambda.tf (80%) rename sns.tf => aws-sns.tf (100%) diff --git a/alarms.tf b/aws-alarms.tf similarity index 77% rename from alarms.tf rename to aws-alarms.tf index e10040d..1b8d335 100644 --- a/alarms.tf +++ b/aws-alarms.tf @@ -13,6 +13,6 @@ resource "aws_cloudformation_stack" "cloudtrail_alarm" { parameters = { CloudTrailLogGroupName = var.cloudtrail_log_group_name - AlarmNotificationTopic = try(aws_sns_topic.alarms[0].arn, var.alarm_notification_sns_topic) + AlarmNotificationTopic = length(var.alarm_notification_sns_topic) > 0 ? var.alarm_notification_sns_topic : try(aws_sns_topic.alarms[0].arn, "") } } diff --git a/event_bridge.tf b/aws-event_bridge.tf similarity index 94% rename from event_bridge.tf rename to aws-event_bridge.tf index 693421c..19d27b8 100644 --- a/event_bridge.tf +++ b/aws-event_bridge.tf @@ -25,6 +25,6 @@ resource "aws_cloudwatch_event_rule" "alarm_notification" { resource "aws_cloudwatch_event_target" "lambda_target" { count = length(var.endpoints) > 0 ? 1 : 0 rule = aws_cloudwatch_event_rule.alarm_notification[0].name - target_id = "NotifyLambda" + target_id = "cloudtrail_alarm_notifications" arn = var.alarm_protocol == "email" ? aws_lambda_function.lambda[0].arn : aws_sns_topic.alarms[0].arn } diff --git a/iam.tf b/aws-iam.tf similarity index 82% rename from iam.tf rename to aws-iam.tf index f572747..b1c5514 100644 --- a/iam.tf +++ b/aws-iam.tf @@ -1,5 +1,5 @@ data "aws_iam_policy_document" "lambda_assume_role" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 statement { actions = ["sts:AssumeRole"] principals { @@ -10,14 +10,14 @@ data "aws_iam_policy_document" "lambda_assume_role" { } resource "aws_iam_role" "iam_for_lambda" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-role-${data.aws_region.current.name}" assume_role_policy = data.aws_iam_policy_document.lambda_assume_role[0].json tags = var.tags } resource "aws_iam_policy" "lambda_cw" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-policy-${data.aws_region.current.name}" path = "/" description = "IAM policy for logging from a lambda" @@ -53,7 +53,7 @@ resource "aws_iam_policy" "lambda_cw" { } resource "aws_iam_role_policy_attachment" "lambda_cw" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 role = aws_iam_role.iam_for_lambda[0].name policy_arn = aws_iam_policy.lambda_cw[0].arn } diff --git a/main.tf b/aws-lambda.tf similarity index 80% rename from main.tf rename to aws-lambda.tf index ef906b7..8afdc53 100644 --- a/main.tf +++ b/aws-lambda.tf @@ -1,5 +1,5 @@ resource "aws_lambda_function" "lambda" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 filename = "${path.module}/lambda.zip" function_name = var.lambda_name role = aws_iam_role.iam_for_lambda[0].arn @@ -21,7 +21,7 @@ resource "aws_lambda_function" "lambda" { } resource "aws_lambda_permission" "default" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 statement_id = "AllowExecutionFromEventBridge" action = "lambda:InvokeFunction" function_name = aws_lambda_function.lambda[0].function_name @@ -30,7 +30,7 @@ resource "aws_lambda_permission" "default" { } resource "aws_cloudwatch_log_group" "alarm_lambda" { - count = length(var.endpoints) > 0 ? 1 : 0 + count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 name = "/aws/lambda/${var.lambda_name}" retention_in_days = 365 kms_key_id = var.kms_key diff --git a/sns.tf b/aws-sns.tf similarity index 100% rename from sns.tf rename to aws-sns.tf From 34da9beccc11878f985f78ebb1a5852337c23775 Mon Sep 17 00:00:00 2001 From: Renato Date: Wed, 21 Aug 2024 13:07:40 +1000 Subject: [PATCH 4/5] keep flow with lambda msg --- aws-event_bridge.tf | 4 ++-- aws-iam.tf | 8 ++++---- aws-lambda.tf | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/aws-event_bridge.tf b/aws-event_bridge.tf index 19d27b8..7e27a4a 100644 --- a/aws-event_bridge.tf +++ b/aws-event_bridge.tf @@ -25,6 +25,6 @@ resource "aws_cloudwatch_event_rule" "alarm_notification" { resource "aws_cloudwatch_event_target" "lambda_target" { count = length(var.endpoints) > 0 ? 1 : 0 rule = aws_cloudwatch_event_rule.alarm_notification[0].name - target_id = "cloudtrail_alarm_notifications" - arn = var.alarm_protocol == "email" ? aws_lambda_function.lambda[0].arn : aws_sns_topic.alarms[0].arn + target_id = "lambda_notification" + arn = aws_lambda_function.lambda[0].arn } diff --git a/aws-iam.tf b/aws-iam.tf index b1c5514..f572747 100644 --- a/aws-iam.tf +++ b/aws-iam.tf @@ -1,5 +1,5 @@ data "aws_iam_policy_document" "lambda_assume_role" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 statement { actions = ["sts:AssumeRole"] principals { @@ -10,14 +10,14 @@ data "aws_iam_policy_document" "lambda_assume_role" { } resource "aws_iam_role" "iam_for_lambda" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-role-${data.aws_region.current.name}" assume_role_policy = data.aws_iam_policy_document.lambda_assume_role[0].json tags = var.tags } resource "aws_iam_policy" "lambda_cw" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "cloudtrail-cn-policy-${data.aws_region.current.name}" path = "/" description = "IAM policy for logging from a lambda" @@ -53,7 +53,7 @@ resource "aws_iam_policy" "lambda_cw" { } resource "aws_iam_role_policy_attachment" "lambda_cw" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 role = aws_iam_role.iam_for_lambda[0].name policy_arn = aws_iam_policy.lambda_cw[0].arn } diff --git a/aws-lambda.tf b/aws-lambda.tf index 8afdc53..ef906b7 100644 --- a/aws-lambda.tf +++ b/aws-lambda.tf @@ -1,5 +1,5 @@ resource "aws_lambda_function" "lambda" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 filename = "${path.module}/lambda.zip" function_name = var.lambda_name role = aws_iam_role.iam_for_lambda[0].arn @@ -21,7 +21,7 @@ resource "aws_lambda_function" "lambda" { } resource "aws_lambda_permission" "default" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 statement_id = "AllowExecutionFromEventBridge" action = "lambda:InvokeFunction" function_name = aws_lambda_function.lambda[0].function_name @@ -30,7 +30,7 @@ resource "aws_lambda_permission" "default" { } resource "aws_cloudwatch_log_group" "alarm_lambda" { - count = var.alarm_protocol == "email" && length(var.endpoints) > 0 ? 1 : 0 + count = length(var.endpoints) > 0 ? 1 : 0 name = "/aws/lambda/${var.lambda_name}" retention_in_days = 365 kms_key_id = var.kms_key From e5727ea5bf74ace2018132f85bc41e1281e34afa Mon Sep 17 00:00:00 2001 From: Renato Date: Thu, 22 Aug 2024 19:23:22 +1000 Subject: [PATCH 5/5] Improve FilterPattern for ConsoleSignInWithoutMfaCount and improve Threshold of AuthorizationFailuresAlarm --- cloudtrail-alarms-full.cf.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudtrail-alarms-full.cf.json b/cloudtrail-alarms-full.cf.json index c269ced..8281859 100644 --- a/cloudtrail-alarms-full.cf.json +++ b/cloudtrail-alarms-full.cf.json @@ -285,7 +285,7 @@ "EvaluationPeriods" : "1", "Period" : "300", "Statistic" : "Sum", - "Threshold" : "1" + "Threshold" : "5" } }, @@ -483,7 +483,7 @@ "Type": "AWS::Logs::MetricFilter", "Properties": { "LogGroupName": { "Ref" : "CloudTrailLogGroupName" }, - "FilterPattern": "{ $.eventName = ConsoleLogin && $.additionalEventData.MFAUsed = No }", + "FilterPattern": "{ $.eventName = ConsoleLogin && $.additionalEventData.MFAUsed = No && $.userIdentity.type = IAMUser && $.responseElements.ConsoleLogin = Success }", "MetricTransformations": [ { "MetricNamespace": "CloudTrailMetrics",