Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions modules/collections/local.tf
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,47 @@ locals {

create_common_sns_topic = local.create_common_bucket && (local.create_elb_source || local.create_classic_lb_source || local.create_cloudtrail_source)

# --- Existing Bucket Detection ---
any_existing_bucket_source = (
(local.create_cloudtrail_source && !var.cloudtrail_source_details.bucket_details.create_bucket) ||
(local.create_elb_source && !var.elb_source_details.bucket_details.create_bucket) ||
(local.create_classic_lb_source && !var.classic_lb_source_details.bucket_details.create_bucket)
)

# Deduplicated list of existing bucket names (used for IAM resource ARNs)
existing_bucket_names = distinct(compact([
local.create_cloudtrail_source && !var.cloudtrail_source_details.bucket_details.create_bucket ? var.cloudtrail_source_details.bucket_details.bucket_name : "",
local.create_elb_source && !var.elb_source_details.bucket_details.create_bucket ? var.elb_source_details.bucket_details.bucket_name : "",
local.create_classic_lb_source && !var.classic_lb_source_details.bucket_details.create_bucket ? var.classic_lb_source_details.bucket_details.bucket_name : "",
]))

# Map keyed by "bucket_name-service_type" — one AddBucketPolicy invocation per source
existing_bucket_policy_map = {
for entry in concat(
local.create_cloudtrail_source && !var.cloudtrail_source_details.bucket_details.create_bucket ? [{ bucket_name = var.cloudtrail_source_details.bucket_details.bucket_name, service_type = "CloudTrail" }] : [],
local.create_elb_source && !var.elb_source_details.bucket_details.create_bucket ? [{ bucket_name = var.elb_source_details.bucket_details.bucket_name, service_type = "ALB" }] : [],
local.create_classic_lb_source && !var.classic_lb_source_details.bucket_details.create_bucket ? [{ bucket_name = var.classic_lb_source_details.bucket_details.bucket_name, service_type = "ELB" }] : [],
) : "${entry.bucket_name}-${entry.service_type}" => entry
}

# Sources list for ConfigureBucketNotifications Lambda (populated after child modules create sources)
existing_bucket_sources = [
for entry in [
local.create_cloudtrail_source && !var.cloudtrail_source_details.bucket_details.create_bucket ? {
BucketName = var.cloudtrail_source_details.bucket_details.bucket_name
SumoEndpoint = module.cloudtrail_module["cloudtrail_module"].sumologic_source.url
} : null,
local.create_elb_source && !var.elb_source_details.bucket_details.create_bucket ? {
BucketName = var.elb_source_details.bucket_details.bucket_name
SumoEndpoint = module.elb_module["elb_module"].sumologic_source.url
} : null,
local.create_classic_lb_source && !var.classic_lb_source_details.bucket_details.create_bucket ? {
BucketName = var.classic_lb_source_details.bucket_details.bucket_name
SumoEndpoint = module.classic_lb_module["classic_lb_module"].sumologic_source.url
} : null,
] : entry if entry != null
]

# Create an IAM role that provides trust relationship with AWS account
create_iam_role = var.existing_iam_details.create_iam_role && (local.create_elb_source || local.create_classic_lb_source || local.create_cloudtrail_source || local.create_kf_metrics_source || local.create_cw_metrics_source)

Expand Down
21 changes: 15 additions & 6 deletions modules/collections/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module "cloudtrail_module" {


create_collector = false
create_trail = var.cloudtrail_source_details.bucket_details.create_bucket ? true : false
create_trail = var.cloudtrail_source_details.bucket_details.create_trail
sumologic_organization_id = var.sumologic_organization_id
wait_for_seconds = 1

Expand All @@ -64,11 +64,14 @@ module "cloudtrail_module" {
iam_role_arn = local.create_iam_role ? aws_iam_role.sumologic_iam_role["sumologic_iam_role"].arn : var.existing_iam_details.iam_role_arn
}
sns_topic_details = {
create_sns_topic = var.cloudtrail_source_details.bucket_details.create_bucket ? false : true
create_sns_topic = false
sns_topic_arn = var.cloudtrail_source_details.bucket_details.create_bucket ? aws_sns_topic.sns_topic["sns_topic"].arn : ""
}
}
aws_resource_tags = var.aws_resource_tags
create_sns_subscription = var.cloudtrail_source_details.bucket_details.create_bucket
create_existing_bucket_policy = false
create_existing_bucket_notification = false
aws_resource_tags = var.aws_resource_tags
}

# #ALB module
Expand Down Expand Up @@ -109,10 +112,13 @@ module "elb_module" {
iam_role_arn = local.create_iam_role ? aws_iam_role.sumologic_iam_role["sumologic_iam_role"].arn : var.existing_iam_details.iam_role_arn
}
sns_topic_details = {
create_sns_topic = var.elb_source_details.bucket_details.create_bucket ? false : true
create_sns_topic = false
sns_topic_arn = var.elb_source_details.bucket_details.create_bucket ? aws_sns_topic.sns_topic["sns_topic"].arn : ""
}
}
create_sns_subscription = var.elb_source_details.bucket_details.create_bucket
create_existing_bucket_policy = false
create_existing_bucket_notification = false

auto_enable_access_logs = var.auto_enable_access_logs
app_semantic_version = "1.0.19"
Expand Down Expand Up @@ -161,11 +167,14 @@ module "classic_lb_module" {
iam_role_arn = local.create_iam_role ? aws_iam_role.sumologic_iam_role["sumologic_iam_role"].arn : var.existing_iam_details.iam_role_arn
}
sns_topic_details = {
create_sns_topic = var.classic_lb_source_details.bucket_details.create_bucket ? false : true
create_sns_topic = false
sns_topic_arn = var.classic_lb_source_details.bucket_details.create_bucket ? aws_sns_topic.sns_topic["sns_topic"].arn : ""
}
}
auto_enable_access_logs = var.auto_enable_classic_lb_access_logs
create_sns_subscription = var.classic_lb_source_details.bucket_details.create_bucket
create_existing_bucket_policy = false
create_existing_bucket_notification = false
auto_enable_access_logs = var.auto_enable_classic_lb_access_logs
app_semantic_version = "1.0.19"
auto_enable_access_logs_options = {
bucket_prefix = local.auto_classic_lb_path_exp
Expand Down
100 changes: 100 additions & 0 deletions modules/collections/main_lambda_helper.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
locals {
region_bucket_map = {
"us-east-1" = "appdevzipfiles-us-east-1"
"us-east-2" = "appdevzipfiles-us-east-2"
"us-west-1" = "appdevzipfiles-us-west-1"
"us-west-2" = "appdevzipfiles-us-west-2"
"ap-south-1" = "appdevzipfiles-ap-south-1"
"ap-northeast-2" = "appdevzipfiles-ap-northeast-2"
"ap-southeast-1" = "appdevzipfiles-ap-southeast-1"
"ap-southeast-2" = "appdevzipfiles-ap-southeast-2"
"ap-northeast-1" = "appdevzipfiles-ap-northeast-1"
"ca-central-1" = "appdevzipfiles-ca-central-1"
"eu-central-1" = "appdevzipfiles-eu-central-1"
"eu-west-1" = "appdevzipfiles-eu-west-1"
"eu-west-2" = "appdevzipfiles-eu-west-2"
"eu-west-3" = "appdevzipfiles-eu-west-3"
"eu-north-1" = "appdevzipfiles-eu-north-1s"
"sa-east-1" = "appdevzipfiles-sa-east-1"
"ap-east-1" = "appdevzipfiles-ap-east-1s"
"af-south-1" = "appdevzipfiles-af-south-1s"
"eu-south-1" = "appdevzipfiles-eu-south-1"
"me-south-1" = "appdevzipfiles-me-south-1s"
"me-central-1" = "appdevzipfiles-me-central-1"
"eu-central-2" = "appdevzipfiles-eu-central-2ss"
"ap-northeast-3" = "appdevzipfiles-ap-northeast-3s"
"ap-southeast-3" = "appdevzipfiles-ap-southeast-3"
"il-central-1" = "appdevzipfiles-il-central-1"
"ap-southeast-4" = "appdevzipfiles-ap-southeast-4s"
"ap-southeast-6" = "appdevzipfiles-ap-southeast-6ss"
}
}

resource "aws_iam_role" "lambda_helper_role" {
for_each = toset(local.any_existing_bucket_source ? ["lambda_helper"] : [])

name = "SumoLogic-AWSO-LambdaHelper-${random_string.aws_random.id}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
tags = var.aws_resource_tags
}

resource "aws_iam_role_policy" "lambda_helper_policy" {
for_each = toset(local.any_existing_bucket_source ? ["lambda_helper"] : [])

name = "SumoLogic-AWSO-LambdaHelper-Policy"
role = aws_iam_role.lambda_helper_role["lambda_helper"].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
Resource = "arn:${data.aws_partition.current.partition}:logs:*:*:*"
},
{
Effect = "Allow"
Action = [
"sns:CreateTopic",
"sns:DeleteTopic",
"sns:SetTopicAttributes",
"sns:Subscribe",
"sns:Unsubscribe",
"sns:ListSubscriptionsByTopic",
]
Resource = "arn:${data.aws_partition.current.partition}:sns:${local.aws_region}:${local.aws_account_id}:sumo-s3-notif-*"
},
{
Effect = "Allow"
Action = [
"s3:GetBucketNotification",
"s3:PutBucketNotification",
"s3:GetBucketPolicy",
"s3:PutBucketPolicy",
"s3:DeleteBucketPolicy",
]
Resource = [for b in local.existing_bucket_names : "arn:${data.aws_partition.current.partition}:s3:::${b}"]
},
]
})
}

resource "aws_lambda_function" "lambda_helper" {
for_each = toset(local.any_existing_bucket_source ? ["lambda_helper"] : [])

function_name = "SumoLogic-AWSO-Helper-${random_string.aws_random.id}"
handler = "main.handler"
runtime = "python3.14"
timeout = 300
memory_size = 128
role = aws_iam_role.lambda_helper_role["lambda_helper"].arn
s3_bucket = local.region_bucket_map[local.aws_region]
s3_key = "sumologic-aws-observability/functions/sumo-app-utils/v3.0.0/sumo-app-utils.zip"
tags = var.aws_resource_tags
}
43 changes: 43 additions & 0 deletions modules/collections/main_s3_bucket.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,47 @@ resource "aws_s3_bucket_notification" "bucket_notification" {
topic_arn = aws_sns_topic.sns_topic["sns_topic"].arn
events = ["s3:ObjectCreated:Put"]
}
}

# --- Existing Bucket Handling (via Lambda) ---

resource "aws_lambda_invocation" "add_bucket_policy" {
for_each = local.existing_bucket_policy_map

depends_on = [aws_lambda_function.lambda_helper]
function_name = aws_lambda_function.lambda_helper["lambda_helper"].function_name
input = jsonencode({
ResourceType = "Custom::AddBucketPolicy"
ResourceProperties = {
BucketName = each.value.bucket_name
Partition = data.aws_partition.current.partition
ServiceType = each.value.service_type
}
})

lifecycle_scope = "CRUD"
}

resource "aws_lambda_invocation" "configure_bucket_notifications" {
for_each = toset(local.any_existing_bucket_source ? ["configure"] : [])

depends_on = [
aws_lambda_function.lambda_helper,
module.cloudtrail_module,
module.elb_module,
module.classic_lb_module,
]
function_name = aws_lambda_function.lambda_helper["lambda_helper"].function_name
input = jsonencode({
ResourceType = "Custom::ConfigureBucketNotifications"
ResourceProperties = {
Region = local.aws_region
AccountId = local.aws_account_id
Partition = data.aws_partition.current.partition
StackId = "terraform/${random_string.aws_random.id}"
Sources = local.existing_bucket_sources
}
})

lifecycle_scope = "CRUD"
}
3 changes: 3 additions & 0 deletions modules/collections/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ variable "cloudtrail_source_details" {
description = string
bucket_details = object({
create_bucket = bool
create_trail = bool
bucket_name = string
path_expression = string
force_destroy_bucket = bool
Expand All @@ -195,6 +196,7 @@ variable "cloudtrail_source_details" {
To enable, set collect_cloudtrail_logs to true and provide configuration information for the bucket at bucket_details.
If create_bucket is false, provide a name of an existing S3 bucket where you would like to store CloudTrail logs. If this is empty, a new bucket will be created in the region.
If create_bucket is true, the script creates a bucket, the name of the bucket has to be unique; this is achieved internally by generating a random-id and then post-fixing it to the “aws-observability-” string.
create_trail - Set to true to create a new AWS CloudTrail trail. Set to false if a trail already exists writing to the bucket.
path_expression - This is required in case the above existing bucket is already configured to receive CloudTrail logs. If this is blank, Sumo Logic will store logs in the path expression AWSLogs/*/CloudTrail/*/*.
EOT
default = {
Expand All @@ -203,6 +205,7 @@ variable "cloudtrail_source_details" {
description = "This source is created using Sumo Logic terraform AWS Observability module to collect AWS cloudtrail logs."
bucket_details = {
create_bucket = true
create_trail = true
bucket_name = "aws-observability-random-id"
path_expression = "AWSLogs/<ACCOUNT-ID>/CloudTrail/<REGION-NAME>/*"
force_destroy_bucket = true
Expand Down
Loading