diff --git a/modules/integrations/cloud-logs/main.tf b/modules/integrations/cloud-logs/main.tf index f4b9503..c8de57b 100644 --- a/modules/integrations/cloud-logs/main.tf +++ b/modules/integrations/cloud-logs/main.tf @@ -1,13 +1,20 @@ #----------------------------------------------------------------------------------------------------------------------- -# The only resource needed to make Sysdig's backend start to fetch data from the CloudTrail associated s3 bucket is a -# properly set AWS IAM Role. Sysdig's trusted identity act as the Principal in the assume role Policy, namely the role -# that the backend will use to assume the Client's role. At that point, given the permission set granted to the newly -# created Role in the Client's account, Sysdig's backend will be able to perform all the required actions in order to -# retrieve the log files that are automatically published in the target s3 bucket. +# This Terraform module creates the necessary resources to enable Sysdig's backend to fetch data from the +# CloudTrail-associated S3 bucket in the customer's AWS account. The setup includes: # -# Note: this setup assumes that the Customer has already properly set up an AWS CloudTrail Trail and the associated bucket. -# Sysdig's Secure UI provides the necessary information to make the Customer perform the -# required setup operations before applying the Terraform module. +# 1. An AWS IAM Role with the appropriate permissions to allow Sysdig's backend to access the S3 bucket where +# CloudTrail logs are stored. Sysdig's trusted identity is specified as the Principal in the assume role policy, +# enabling the backend to assume the role in the customer account and perform required actions. +# +# 2. An AWS SNS Topic and Subscription for CloudTrail notifications, ensuring Sysdig's backend is notified whenever +# new logs are published to the S3 bucket. The SNS Topic allows CloudTrail to publish notifications, while the +# subscription forwards these notifications to Sysdig's ingestion service via HTTPS. +# +# This setup assumes the customer has already configured an AWS CloudTrail Trail and its associated S3 bucket. The +# required details (e.g., bucket ARN, topic ARN, and regions) are either passed as module variables or derived from +# data sources. +# +# Note: Sysdig's Secure UI provides the necessary information to guide customers in setting up the required resources. #----------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------- @@ -21,14 +28,25 @@ data "sysdig_secure_trusted_cloud_identity" "trusted_identity" { data "sysdig_secure_tenant_external_id" "external_id" {} +data "sysdig_secure_cloud_ingestion_assets" "assets" { + cloud_provider = "aws" + cloud_provider_id = data.aws_caller_identity.current.account_id +} + #----------------------------------------------------------------------------------------- # Generate a unique name for resources using random suffix and account ID hash #----------------------------------------------------------------------------------------- locals { account_id_hash = substr(md5(data.aws_caller_identity.current.account_id), 0, 4) - role_name = "${var.name}-${random_id.suffix.hex}-${local.account_id_hash}" - bucket_arn = regex("^([^/]+)", var.folder_arn)[0] - trusted_identity = var.is_gov_cloud_onboarding ? data.sysdig_secure_trusted_cloud_identity.trusted_identity.gov_identity : data.sysdig_secure_trusted_cloud_identity.trusted_identity.identity + role_name = "${var.name}-${random_id.suffix.hex}-${local.account_id_hash}" + bucket_arn = regex("^([^/]+)", var.folder_arn)[0] + bucket_name = var.is_gov_cloud_onboarding ? replace(local.bucket_arn, "arn:aws-us-gov:s3:::", "") : replace(local.bucket_arn, "arn:aws:s3:::", "") + bucket_region = data.aws_s3_bucket.cloudtrail_bucket.region + trusted_identity = var.is_gov_cloud_onboarding ? data.sysdig_secure_trusted_cloud_identity.trusted_identity.gov_identity : data.sysdig_secure_trusted_cloud_identity.trusted_identity.identity + + topic_name = split(":", var.topic_arn)[5] + routing_key = data.sysdig_secure_cloud_ingestion_assets.assets.aws.sns_routing_key + ingestion_url = data.sysdig_secure_cloud_ingestion_assets.assets.aws.sns_routing_url } #----------------------------------------------------------------------------------------------------------------------- @@ -41,8 +59,8 @@ resource "random_id" "suffix" { # AWS IAM Role that will be used by CloudIngestion to access the CloudTrail-associated s3 bucket resource "aws_iam_role" "cloudlogs_s3_access" { - name = local.role_name - tags = var.tags + name = local.role_name + tags = var.tags assume_role_policy = data.aws_iam_policy_document.assume_cloudlogs_s3_access_role.json } @@ -89,40 +107,67 @@ data "aws_iam_policy_document" "cloudlogs_s3_access" { "${local.bucket_arn}/*" ] } +} - statement { - sid = "CloudlogsS3AccessList" +# Fetch the S3 bucket information +data "aws_s3_bucket" "cloudtrail_bucket" { + bucket = local.bucket_name +} - effect = "Allow" +#----------------------------------------------------------------------------------------------------------------------- +# SNS Topic and Subscription for CloudTrail notifications +#----------------------------------------------------------------------------------------------------------------------- +resource "aws_sns_topic" "cloudtrail_notifications" { + count = var.create_topic ? 1 : 0 + name = local.topic_name + tags = var.tags +} - actions = [ - "s3:List*" +resource "aws_sns_topic_policy" "cloudtrail_notifications" { + count = var.create_topic ? 1 : 0 + arn = aws_sns_topic.cloudtrail_notifications[0].arn + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowCloudTrailPublish" + Effect = "Allow" + Principal = { + Service = "cloudtrail.amazonaws.com" + } + Action = "SNS:Publish" + Resource = aws_sns_topic.cloudtrail_notifications[0].arn + } ] + }) +} - resources = [ - local.bucket_arn, - "${local.bucket_arn}/*" - ] - } +resource "aws_sns_topic_subscription" "cloudtrail_notifications" { + topic_arn = var.topic_arn + protocol = "https" + endpoint = local.ingestion_url + + depends_on = [aws_sns_topic.cloudtrail_notifications] } #----------------------------------------------------------------------------------------------------------------------------------------- -# Call Sysdig Backend to add the cloud logs integration to the Sysdig Cloud Account -# -# Note (optional): To ensure this gets called after all cloud resources are created, add -# explicit dependency using depends_on +# Call Sysdig Backend to add the cloud logs integration #----------------------------------------------------------------------------------------------------------------------------------------- resource "sysdig_secure_cloud_auth_account_component" "aws_cloud_logs" { - account_id = var.sysdig_secure_account_id - type = "COMPONENT_CLOUD_LOGS" - instance = "secure-runtime" - version = "v0.1.0" + account_id = var.sysdig_secure_account_id + type = "COMPONENT_CLOUD_LOGS" + instance = "secure-runtime" + version = "v1.0.0" cloud_logs_metadata = jsonencode({ aws = { - cloudtrailS3Bucket = { - folder_arn = var.folder_arn - role_name = local.role_name - regions = var.regions + cloudtrailSns = { + role_name = local.role_name + topic_arn = var.topic_arn + subscription_arn = aws_sns_topic_subscription.cloudtrail_notifications.arn + bucket_region = local.bucket_region + bucket_arn = local.bucket_arn + ingested_regions = var.regions + routing_key = local.routing_key } } }) diff --git a/modules/integrations/cloud-logs/variables.tf b/modules/integrations/cloud-logs/variables.tf index c78ff5c..c7ab304 100644 --- a/modules/integrations/cloud-logs/variables.tf +++ b/modules/integrations/cloud-logs/variables.tf @@ -34,3 +34,24 @@ variable "is_gov_cloud_onboarding" { default = false description = "true/false whether secure-for-cloud should be deployed in a govcloud account/org or not" } + +variable "topic_arn" { + type = string + description = "SNS Topic ARN that will forward CloudTrail notifications to Sysdig Secure" + + validation { + condition = var.topic_arn != "" + error_message = "Topic ARN must not be empty" + } + + validation { + condition = can(regex("^arn:(aws|aws-us-gov):sns:[a-z0-9-]+:[0-9]+:.+$", var.topic_arn)) + error_message = "Topic ARN must be a valid SNS ARN format" + } +} + +variable "create_topic" { + type = bool + default = false + description = "true/false whether terraform should create the SNS Topic" +} diff --git a/modules/integrations/cloud-logs/versions.tf b/modules/integrations/cloud-logs/versions.tf index ebd9364..a9e8fb1 100644 --- a/modules/integrations/cloud-logs/versions.tf +++ b/modules/integrations/cloud-logs/versions.tf @@ -8,7 +8,7 @@ terraform { } sysdig = { source = "sysdiglabs/sysdig" - version = "~> 1.39" + version = "~> 1.44" } random = { source = "hashicorp/random"