Skip to content

Commit

Permalink
Fix email conditional to allow email-only or chatbot-only deployment
Browse files Browse the repository at this point in the history
  • Loading branch information
adenot committed Jul 26, 2024
1 parent 5ed4409 commit bcc801f
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 68 deletions.
7 changes: 1 addition & 6 deletions _outputs.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
output "lambda_arn" {
description = "The ARN from lambda custom message"
value = aws_lambda_function.lambda.arn
}

output "alarm_sns_topic" {
description = "The SNS topic to which CloudWatch Alarms will be sent."
value = aws_sns_topic.alarms
value = aws_lambda_function.lambda[*].arn
}
18 changes: 0 additions & 18 deletions _variables.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
variable "enabled" {
description = "The boolean flag whether this module is enabled or not. No resources are created when set to false."
type = bool
default = true
}

variable "lambda_name" {
description = "The name of the lambda which will be notified with a custom message when any alarm is performed."
type = string
Expand Down Expand Up @@ -33,23 +27,11 @@ variable "chatbot_sns_topic" {
default = ""
}

# variable "email_sns_topic" {
# description = "The arn of the SNS Topic which will be notified when any alarm is performed via email."
# type = string
# default = ""
# }

variable "emails" {
default = []
type = list(string)
}


variable "alarm_account_ids" {
default = []
type = list(string)
}

variable "alarm_mode" {
default = "light"
type = string
Expand Down
6 changes: 2 additions & 4 deletions alarms.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

resource "random_string" "cloudtrail_alarm_suffix" {
count = var.enabled ? 1 : 0
length = 8
special = false
lower = true
Expand All @@ -9,12 +8,11 @@ resource "random_string" "cloudtrail_alarm_suffix" {
}

resource "aws_cloudformation_stack" "cloudtrail_alarm" {

Check failure on line 10 in alarms.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_124: "Ensure that CloudFormation stacks are sending event notifications to an SNS topic"
count = var.enabled ? 1 : 0
name = "cloudtrail-alarm-${random_string.cloudtrail_alarm_suffix[0].result}"
name = "cloudtrail-alarm-${random_string.cloudtrail_alarm_suffix.result}"
template_body = var.alarm_mode == "full" ? file("${path.module}/cloudtrail-alarms-full.cf.json") : file("${path.module}/cloudtrail-alarms-light.cf.yml")

parameters = {
CloudTrailLogGroupName = var.cloudtrail_log_group_name
AlarmNotificationTopic = var.chatbot_sns_topic # aws_sns_topic.alarms[0].id
AlarmNotificationTopic = var.chatbot_sns_topic
}
}
39 changes: 22 additions & 17 deletions cloudtrail-alarms-full.cf.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
"Description": "SNS Notification Topic to send alarms to"
}
},
"Conditions": {
"HasAlarmNotificationTopic": {
"Fn::Not": [{ "Fn::Equals": [{ "Ref": "AlarmNotificationTopic" }, ""] }]
}
},
"Resources" : {
"SecurityGroupChangesMetricFilter": {
"Type": "AWS::Logs::MetricFilter",
Expand All @@ -31,7 +36,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailSecurityGroupChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a Security Group.",
"MetricName" : "SecurityGroupEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -61,7 +66,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailNetworkAclChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a Network ACL.",
"MetricName" : "NetworkAclEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -91,7 +96,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailGatewayChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a Customer or Internet Gateway.",
"MetricName" : "GatewayEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -121,7 +126,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailVpcChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a VPC, VPC peering connection or VPC connection to classic.",
"MetricName" : "VpcEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -151,7 +156,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailEC2InstanceChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, terminate, start, stop or reboot an EC2 instance.",
"MetricName" : "EC2InstanceEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -181,7 +186,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailEC2LargeInstanceChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, terminate, start, stop or reboot a 4x or 8x-large EC2 instance.",
"MetricName" : "EC2LargeInstanceEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -211,7 +216,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a CloudTrail trail, or to start or stop logging to a trail.",
"MetricName" : "CloudTrailEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -242,7 +247,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailConsoleSignInFailuresV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an unauthenticated API call is made to sign into the console.",
"MetricName" : "ConsoleSignInFailureCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -273,7 +278,7 @@
"Properties": {
"AlarmName" : "CloudTrailAuthorizationFailuresV2",
"AlarmDescription" : "Alarms when an unauthorized API call is made.",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"MetricName" : "AuthorizationFailureCount",
"Namespace" : "CloudTrailMetrics",
"ComparisonOperator" : "GreaterThanOrEqualToThreshold",
Expand Down Expand Up @@ -303,7 +308,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailIAMPolicyChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to change an IAM policy.",
"MetricName" : "IAMPolicyEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -333,7 +338,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CloudTrailRouteTableChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms when an API call is made to create, update or delete a Route Table.",
"MetricName" : "RouteTableEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -363,7 +368,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "CMKChangesV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms each time when a CMK configuration change is made.",
"MetricName" : "CMKEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -393,7 +398,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "RootAccountUsageAlarmV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Alarms each time when Root Account is used.",
"MetricName" : "RootAccountUsageEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -425,7 +430,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "AWSConfigChangesAlarmV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Triggered by AWS Config changes.",
"MetricName" : "ConfigEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -458,7 +463,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "S3BucketConfigChangesAlarmV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Triggered by AWS S3 Bucket config changes.",
"MetricName" : "S3BucketEventCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -492,7 +497,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "ConsoleSignInWithoutMfaAlarmV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Triggered by sign-in requests made without MFA.",
"MetricName" : "ConsoleSignInWithoutMfaCount",
"Namespace" : "CloudTrailMetrics",
Expand Down Expand Up @@ -526,7 +531,7 @@
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName" : "OrganizationsChangesAlarmV2",
"AlarmActions": [{"Ref" : "AlarmNotificationTopic"}],
"AlarmActions": { "Fn::If" : [ "HasAlarmNotificationTopic", [{"Ref" : "AlarmNotificationTopic"}], { "Ref": "AWS::NoValue" } ] },
"AlarmDescription" : "Triggered by AWS Organizations events.",
"MetricName" : "OrganizationsEvents",
"Namespace" : "CloudTrailMetrics",
Expand Down
10 changes: 6 additions & 4 deletions cloudtrail-alarms-light.cf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ Parameters:
AlarmNotificationTopic:
Type: String
Description: SNS Notification Topic to send alarms to
Default: ""

Conditions:
HasAlarmNotificationTopic: !Not [!Equals [!Ref AlarmNotificationTopic, ""]]

#====================================================================================================
Resources:
Expand All @@ -31,8 +35,7 @@ Resources:
Properties:
AlarmName: RootAccountUsage
AlarmDescription: (CIS-3.3) Alarms when Root Account is used
AlarmActions:
- !Ref AlarmNotificationTopic
AlarmActions: !If [HasAlarmNotificationTopic, [!Ref AlarmNotificationTopic], !Ref AWS::NoValue]
MetricName: RootAccountUsageEventCount
Namespace: CloudTrailMetrics
ComparisonOperator: GreaterThanOrEqualToThreshold
Expand All @@ -57,8 +60,7 @@ Resources:
Properties:
AlarmName: NoMFALogin
AlarmDescription: Monitoring for single-factor console logins will increase visibility into accounts that are not protected by MFA.
AlarmActions:
- !Ref AlarmNotificationTopic
AlarmActions: !If [HasAlarmNotificationTopic, [!Ref AlarmNotificationTopic], !Ref AWS::NoValue]
MetricName: NoMFALoginEventCount
Namespace: CloudTrailMetrics
ComparisonOperator: GreaterThanOrEqualToThreshold
Expand Down
8 changes: 5 additions & 3 deletions event_bridge.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
resource "aws_cloudwatch_event_rule" "alarm_notification" {
count = length(var.emails) > 0 ? 1 : 0
name = "cloudtrail_alarm_custom_notifications"
description = "Will be notified with a custom message when any alarm is performed"
is_enabled = true

event_pattern = <<PATTERN
{
Expand All @@ -21,8 +21,10 @@ resource "aws_cloudwatch_event_rule" "alarm_notification" {
}
PATTERN
}

resource "aws_cloudwatch_event_target" "lambda_target" {
rule = aws_cloudwatch_event_rule.alarm_notification.name
count = length(var.emails) > 0 ? 1 : 0
rule = aws_cloudwatch_event_rule.alarm_notification[0].name
target_id = "NotifyLambda"
arn = aws_lambda_function.lambda.arn
arn = aws_lambda_function.lambda[0].arn
}
12 changes: 8 additions & 4 deletions iam.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
data "aws_iam_policy_document" "lambda_assume_role" {
count = length(var.emails) > 0 ? 1 : 0
statement {
actions = ["sts:AssumeRole"]
principals {
Expand All @@ -9,12 +10,14 @@ data "aws_iam_policy_document" "lambda_assume_role" {
}

resource "aws_iam_role" "iam_for_lambda" {
count = length(var.emails) > 0 ? 1 : 0
name = "cloudtrail-cn-role-${data.aws_region.current.name}"
assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json
assume_role_policy = data.aws_iam_policy_document.lambda_assume_role[0].json
tags = var.tags
}

resource "aws_iam_policy" "lambda_cw" {

Check failure on line 19 in iam.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_290: "Ensure IAM policies does not allow write access without constraints"

Check failure on line 19 in iam.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_355: "Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions"
count = length(var.emails) > 0 ? 1 : 0
name = "cloudtrail-cn-policy-${data.aws_region.current.name}"
path = "/"
description = "IAM policy for logging from a lambda"
Expand All @@ -32,7 +35,7 @@ resource "aws_iam_policy" "lambda_cw" {
"logs:DescribeMetricFilters",
"logs:FilterLogEvents"
],
Resource : [aws_lambda_function.lambda.arn, "arn:aws:logs:*:*:*", "arn:aws:cloudwatch:*:*:*"]
Resource : [aws_lambda_function.lambda[0].arn, "arn:aws:logs:*:*:*", "arn:aws:cloudwatch:*:*:*"]
Effect : "Allow"
},
{
Expand All @@ -50,6 +53,7 @@ resource "aws_iam_policy" "lambda_cw" {
}

resource "aws_iam_role_policy_attachment" "lambda_cw" {
role = aws_iam_role.iam_for_lambda.name
policy_arn = aws_iam_policy.lambda_cw.arn
count = length(var.emails) > 0 ? 1 : 0
role = aws_iam_role.iam_for_lambda[0].name
policy_arn = aws_iam_policy.lambda_cw[0].arn
}
9 changes: 6 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
resource "aws_lambda_function" "lambda" {

Check failure on line 1 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_272: "Ensure AWS Lambda function is configured to validate code-signing"

Check failure on line 1 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_173: "Check encryption settings for Lambda environmental variable"

Check failure on line 1 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_117: "Ensure that AWS Lambda function is configured inside a VPC"

Check failure on line 1 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_116: "Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)"

Check failure on line 1 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_115: "Ensure that AWS Lambda function is configured for function-level concurrent execution limit"
count = length(var.emails) > 0 ? 1 : 0
filename = "${path.module}/lambda.zip"
function_name = var.lambda_name
role = aws_iam_role.iam_for_lambda.arn
role = aws_iam_role.iam_for_lambda[0].arn
handler = "index.handler"
timeout = var.lambda_timeout
source_code_hash = filebase64sha256("${path.module}/lambda.zip")
Expand All @@ -20,14 +21,16 @@ resource "aws_lambda_function" "lambda" {
}

resource "aws_lambda_permission" "default" {
count = length(var.emails) > 0 ? 1 : 0
statement_id = "AllowExecutionFromEventBridge"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.lambda.function_name
function_name = aws_lambda_function.lambda[0].function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.alarm_notification.arn
source_arn = aws_cloudwatch_event_rule.alarm_notification[0].arn
}

resource "aws_cloudwatch_log_group" "alarm_lambda" {

Check failure on line 32 in main.tf

View workflow job for this annotation

GitHub Actions / scan

CKV_AWS_158: "Ensure that CloudWatch Log Group is encrypted by KMS"
count = length(var.emails) > 0 ? 1 : 0
name = "/aws/lambda/${var.lambda_name}"
retention_in_days = 365
tags = var.tags
Expand Down
Loading

0 comments on commit bcc801f

Please sign in to comment.