Terraform Notes
Working with Cloudwatch Event Rules
References:
Main file
This is a generic main terraform file that calls the module folder that contains the remainder of the terraform files to be used.
main.tf
main.tf
provider "aws" { region = "us-east-2" } module "cw_event_rules" { source = "./modules/security/cw_event_rules" }
Doing it inline
In order to use JSON string within your tf files, you must start with "<<PATTERN" and end with "PATTERN"
/modules/security/cw_event_rules/rules_inline.tf
terraform plan
/modules/security/cw_event_rules/rules_external.tf
/modules/security/cw_event_rules/rules_variables.tf
/modules/security/cw_event_rules/jsons/event_rule_console.json
result of terraform plan
/modules/security/cw_event_rules/rules_map.tf
/modules/security/cw_event_rules/rules_variables.tf
result of terraform plan
/modules/security/cw_event_rules/target.tf
result of terraform plan
/modules/security/cw_event_rules/rules_inline.tf
resource "aws_cloudwatch_event_rule" "console" { name = "capture-aws-sign-in" description = "Capture each AWS Console Sign In" event_pattern = <<PATTERN { "detail-type": [ "AWS Console Sign In via CloudTrail" ] } PATTERN }
terraform plan
# module.cw_event_rules.aws_cloudwatch_event_rule.console will be created + resource "aws_cloudwatch_event_rule" "console" { + arn = (known after apply) + description = "Capture each AWS Console Sign In" + event_pattern = jsonencode( { + detail-type = [ + "AWS Console Sign In via CloudTrail", ] } ) + id = (known after apply) + is_enabled = true + name = "capture-aws-sign-in" }
Pulling it in via local_file variable
This method uses a local_file data to pull the content of a file. After local_file is declared, you can call this via data.local_file.yourname.content. This is especially useful if your JSON is large and will probably hinder the readability of your tf file./modules/security/cw_event_rules/rules_external.tf
resource "aws_cloudwatch_event_rule" "console_external" { name = "capture-aws-sign-in" description = "Capture each AWS Console Sign In" event_pattern = data.local_file.event_rule_console.content }
/modules/security/cw_event_rules/rules_variables.tf
data "local_file" "event_rule_console" { filename = "${path.module}/jsons/event_rule_console.json" }
/modules/security/cw_event_rules/jsons/event_rule_console.json
{ "detail-type": [ "AWS Console Sign In via CloudTrail" ] }
result of terraform plan
# module.cw_event_rules.aws_cloudwatch_event_rule.console_external will be created + resource "aws_cloudwatch_event_rule" "console_external" { + arn = (known after apply) + description = "Capture each AWS Console Sign In" + event_pattern = jsonencode( { + detail-type = [ + "AWS Console Sign In via CloudTrail", ] } ) + id = (known after apply) + is_enabled = true + name = "capture-aws-sign-in" }
Pulling it from inside Resources while using List of Maps
This method will NOT rely on the local_file, but instead pull the content directly from the resources block. One of the reason, I did this was I could not fit ${path.module} inside the list-map variable without error./modules/security/cw_event_rules/rules_map.tf
resource "aws_cloudwatch_event_rule" "all_event_rules_map" { count = length(var.event_rules) name = var.event_rules[count.index].name description = var.event_rules[count.index].description event_pattern = file("${path.module}/jsons/${var.event_rules[count.index].filename}") }
/modules/security/cw_event_rules/rules_variables.tf
variable "event_rules" { description = "Create event rules with following names" type = list(map(string)) default = [ { "name"="CIS-UnauthorizedActivityAttempt", "description"="This is the description of 3.1 CIS", "filename"="CIS-UnauthorizedActivityAttempt.json" } { "name"="CIS-ConsoleLoginNoMFA", "description"="This is the description of 3.2 CIS", "filename"="CIS-ConsoleLoginNoMFA.json" } ] }
result of terraform plan
# module.cw_event_rules.aws_cloudwatch_event_rule.all_event_rules_map[0] will be created + resource "aws_cloudwatch_event_rule" "all_event_rules_map" { + arn = (known after apply) + description = "This is the description of 3.1 CIS" + event_pattern = jsonencode( { + detail = { + errorCode = [ + "Client.UnauthorizedOperation", + "AccessDenied", ] } + detail-type = [ + "AWS Console Sign In via CloudTrail", ] } ) + id = (known after apply) + is_enabled = true + name = "CIS-UnauthorizedActivityAttempt" } # module.cw_event_rules.aws_cloudwatch_event_rule.all_event_rules_map[1] will be created + resource "aws_cloudwatch_event_rule" "all_event_rules_map" { + arn = (known after apply) + description = "This is the description of 3.2 CIS" + event_pattern = jsonencode( { + detail = { + additionalEventData = { + MFAUsed = [ + "No", ] } + eventSource = [ + "signin.amazonaws.com", ] + responseElements = { + ConsoleLogin = [ + "Success", ] } } } ) + id = (known after apply) + is_enabled = true + name = "CIS-ConsoleLoginNoMFA" }
Let's add SNS topic as Cloudwatch Events' Target
We're only doing this to List-Map version of the code above. The SNS build code are directly from Terraform doc. Only part that has been edited are the mapping the cloudwatch event rules to target./modules/security/cw_event_rules/target.tf
resource "aws_cloudwatch_event_target" "all_event_rules_map" { count = length(aws_cloudwatch_event_rule.all_event_rules_map) rule = aws_cloudwatch_event_rule.all_event_rules_map[count.index].name target_id = "SendToSNS" arn = "${aws_sns_topic.aws_logins.arn}" } resource "aws_sns_topic" "aws_logins" { name = "aws-console-logins" } resource "aws_sns_topic_policy" "default" { arn = "${aws_sns_topic.aws_logins.arn}" policy = "${data.aws_iam_policy_document.sns_topic_policy.json}" } data "aws_iam_policy_document" "sns_topic_policy" { statement { effect = "Allow" actions = ["SNS:Publish"] principals { type = "Service" identifiers = ["events.amazonaws.com"] } resources = ["${aws_sns_topic.aws_logins.arn}"] } }
result of terraform plan
# module.cw_event_rules.data.aws_iam_policy_document.sns_topic_policy will be read during apply # (config refers to values not yet known) <= data "aws_iam_policy_document" "sns_topic_policy" { + id = (known after apply) + json = (known after apply) + statement { + actions = [ + "SNS:Publish", ] + effect = "Allow" + resources = [ + (known after apply), ] + principals { + identifiers = [ + "events.amazonaws.com", ] + type = "Service" } } } # module.cw_event_rules.aws_sns_topic.aws_logins will be created + resource "aws_sns_topic" "aws_logins" { + arn = (known after apply) + id = (known after apply) + name = "aws-console-logins" + policy = (known after apply) } # module.cw_event_rules.aws_sns_topic_policy.default will be created + resource "aws_sns_topic_policy" "default" { + arn = (known after apply) + id = (known after apply) + policy = (known after apply) } # module.cw_event_rules.aws_cloudwatch_event_target.all_event_rules_map[0] will be created + resource "aws_cloudwatch_event_target" "all_event_rules_map" { + arn = (known after apply) + id = (known after apply) + rule = "CIS-UnauthorizedActivityAttempt" + target_id = "SendToSNS" } # module.cw_event_rules.aws_cloudwatch_event_target.all_event_rules_map[1] will be created + resource "aws_cloudwatch_event_target" "all_event_rules_map" { + arn = (known after apply) + id = (known after apply) + rule = "CIS-ConsoleLoginNoMFA" + target_id = "SendToSNS" }
No comments:
Post a Comment