diff --git a/modules/asm-aws-single/main.tf b/modules/asm-aws-single/main.tf index ebc1dbd..f71bbec 100644 --- a/modules/asm-aws-single/main.tf +++ b/modules/asm-aws-single/main.tf @@ -18,6 +18,7 @@ module "this" { allow_internet_ingress = var.allow_internet_ingress enable_snapshots = var.enable_snapshots marketplace_product_code = var.marketplace_product_code + enable_flow_logs = var.enable_flow_logs # Patching and migration safety create_backup_bucket = var.create_backup_bucket diff --git a/modules/asm-aws-single/outputs.tf b/modules/asm-aws-single/outputs.tf index bf39708..e454388 100644 --- a/modules/asm-aws-single/outputs.tf +++ b/modules/asm-aws-single/outputs.tf @@ -61,3 +61,8 @@ output "pre_patch_ssm_document_name" { value = module.this.pre_patch_ssm_document_name sensitive = false } + +output "flow_log_group_name" { + value = module.this.flow_log_group_name + sensitive = false +} diff --git a/modules/asm-aws-single/variables.tf b/modules/asm-aws-single/variables.tf index c58410b..04249b7 100644 --- a/modules/asm-aws-single/variables.tf +++ b/modules/asm-aws-single/variables.tf @@ -115,6 +115,12 @@ variable "backup_noncurrent_version_expiration_days" { default = 365 } +variable "enable_flow_logs" { + description = "Enable VPC Flow Logs for the provided VPC, sending ALL traffic to a CloudWatch log group. Matches the default stated in SECURITY-DEFAULTS.md." + type = bool + default = true +} + variable "tags" { description = "Additional tags applied to every resource." type = map(string) diff --git a/modules/sat-aws-single/main.tf b/modules/sat-aws-single/main.tf index 1ce4f91..13b6fc2 100644 --- a/modules/sat-aws-single/main.tf +++ b/modules/sat-aws-single/main.tf @@ -18,6 +18,7 @@ module "this" { allow_internet_ingress = var.allow_internet_ingress enable_snapshots = var.enable_snapshots marketplace_product_code = var.marketplace_product_code + enable_flow_logs = var.enable_flow_logs # Patching and migration safety create_backup_bucket = var.create_backup_bucket diff --git a/modules/sat-aws-single/outputs.tf b/modules/sat-aws-single/outputs.tf index bf39708..e454388 100644 --- a/modules/sat-aws-single/outputs.tf +++ b/modules/sat-aws-single/outputs.tf @@ -61,3 +61,8 @@ output "pre_patch_ssm_document_name" { value = module.this.pre_patch_ssm_document_name sensitive = false } + +output "flow_log_group_name" { + value = module.this.flow_log_group_name + sensitive = false +} diff --git a/modules/sat-aws-single/variables.tf b/modules/sat-aws-single/variables.tf index 38db5b9..bfdad23 100644 --- a/modules/sat-aws-single/variables.tf +++ b/modules/sat-aws-single/variables.tf @@ -115,6 +115,12 @@ variable "backup_noncurrent_version_expiration_days" { default = 365 } +variable "enable_flow_logs" { + description = "Enable VPC Flow Logs for the provided VPC, sending ALL traffic to a CloudWatch log group. Matches the default stated in SECURITY-DEFAULTS.md." + type = bool + default = true +} + variable "tags" { description = "Additional tags applied to every resource." type = map(string) diff --git a/modules/single-vm/aws/main.tf b/modules/single-vm/aws/main.tf index aa77b4e..46d1a5e 100644 --- a/modules/single-vm/aws/main.tf +++ b/modules/single-vm/aws/main.tf @@ -424,3 +424,70 @@ resource "aws_ssm_document" "pre_patch_backup" { ] }) } + +# ----- VPC Flow Logs ----- + +resource "aws_cloudwatch_log_group" "flow_logs" { + count = var.enable_flow_logs ? 1 : 0 + name = "/aws/vpc-flow-logs/${local.name_prefix}" + retention_in_days = 30 + kms_key_id = var.enable_customer_managed_key ? aws_kms_key.ebs[0].arn : null + tags = local.common_tags +} + +resource "aws_iam_role" "flow_logs" { + count = var.enable_flow_logs ? 1 : 0 + name = "${local.name_prefix}-flow-logs" + tags = local.common_tags + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { Service = "vpc-flow-logs.amazonaws.com" } + }] + }) +} + +# logs:DescribeLogGroups requires Resource = "*" — the AWS IAM docs explicitly +# state this action does not support resource-level restrictions. +#tfsec:ignore:aws-iam-no-policy-wildcards +resource "aws_iam_role_policy" "flow_logs" { + count = var.enable_flow_logs ? 1 : 0 + name = "${local.name_prefix}-flow-logs" + role = aws_iam_role.flow_logs[0].id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "logs:CreateLogStream", + "logs:PutLogEvents", + "logs:DescribeLogStreams", + ] + Resource = [ + aws_cloudwatch_log_group.flow_logs[0].arn, + "${aws_cloudwatch_log_group.flow_logs[0].arn}:*", + ] + }, + { + Effect = "Allow" + Action = ["logs:DescribeLogGroups"] + Resource = "*" + }, + ] + }) +} + +resource "aws_flow_log" "vpc" { + count = var.enable_flow_logs ? 1 : 0 + iam_role_arn = aws_iam_role.flow_logs[0].arn + log_destination = aws_cloudwatch_log_group.flow_logs[0].arn + log_destination_type = "cloud-watch-logs" + traffic_type = "ALL" + vpc_id = var.vpc_id + tags = local.common_tags +} diff --git a/modules/single-vm/aws/outputs.tf b/modules/single-vm/aws/outputs.tf index c19be80..8a0cee1 100644 --- a/modules/single-vm/aws/outputs.tf +++ b/modules/single-vm/aws/outputs.tf @@ -59,3 +59,8 @@ output "pre_patch_ssm_document_name" { description = "Name of the AWS Systems Manager Run Command document that triggers a pre-patch backup + EBS data-volume snapshot. Run from the Console under Systems Manager -> Run Command, targeting instances tagged hailbytes-=true." value = aws_ssm_document.pre_patch_backup.name } + +output "flow_log_group_name" { + description = "CloudWatch log group name receiving VPC Flow Logs. Empty string when enable_flow_logs is false." + value = var.enable_flow_logs ? aws_cloudwatch_log_group.flow_logs[0].name : "" +} diff --git a/modules/single-vm/aws/variables.tf b/modules/single-vm/aws/variables.tf index 3360b4d..67a01cc 100644 --- a/modules/single-vm/aws/variables.tf +++ b/modules/single-vm/aws/variables.tf @@ -124,6 +124,12 @@ variable "backup_noncurrent_version_expiration_days" { default = 365 } +variable "enable_flow_logs" { + description = "Enable VPC Flow Logs for the provided VPC, sending ALL traffic to a CloudWatch log group named /aws/vpc-flow-logs/. Matches the default stated in SECURITY-DEFAULTS.md." + type = bool + default = true +} + variable "tags" { description = "Additional tags applied to every resource." type = map(string)