Skip to content
115 changes: 80 additions & 35 deletions modules/integrations/cloud-logs/main.tf
Original file line number Diff line number Diff line change
@@ -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.
#-----------------------------------------------------------------------------------------------------------------------

#-----------------------------------------------------------------------------------------
Expand All @@ -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
}

#-----------------------------------------------------------------------------------------------------------------------
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}
}
})
Expand Down
21 changes: 21 additions & 0 deletions modules/integrations/cloud-logs/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
2 changes: 1 addition & 1 deletion modules/integrations/cloud-logs/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ terraform {
}
sysdig = {
source = "sysdiglabs/sysdig"
version = "~> 1.39"
version = "~> 1.44"
}
random = {
source = "hashicorp/random"
Expand Down