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
14 changes: 12 additions & 2 deletions modules/integrations/cloud-logs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ The following resources will be created based on the deployment scenario:
- SNS Topic and Subscription for CloudTrail notifications

3. For organizational cross-account deployments:
- A CloudFormation StackSet that deploys an IAM role directly in the bucket account
- A CloudFormation StackSet that deploys:
- An IAM role in the bucket account (in the current region)
- An SNS subscription in the topic account (in the topic's region)
- The role in the bucket account allows Sysdig to access S3 data directly
- SNS Topic and Subscription for CloudTrail notifications
- The SNS subscription forwards CloudTrail notifications to Sysdig

Additional features include:
- Support for KMS-encrypted S3 buckets by granting the necessary KMS decryption permissions
- Support for AWS GovCloud deployments
- Support for cross-region deployments where the S3 bucket and SNS topic are in different regions

## Important Notes for Cross-Account Access

Expand All @@ -34,6 +37,13 @@ For KMS-encrypted S3 buckets, this module configures the necessary decrypt permi
2. For cross-account scenarios, specify the bucket account ID using the `bucket_account_id` variable
3. Ensure the KMS key policy allows the created role to use the decrypt operation

### Cross-Region Deployments

This module supports deployments where the S3 bucket and SNS topic are in different regions:
- The IAM role will be created in the current region but can access the S3 bucket regardless of its region
- The SNS subscription will be created in the same region as the SNS topic
- The StackSet will deploy to both regions as needed

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

## Requirements
Expand Down
50 changes: 42 additions & 8 deletions modules/integrations/cloud-logs/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,24 @@ data "sysdig_secure_cloud_ingestion_assets" "assets" {
locals {
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]
topic_region = split(":", var.topic_arn)[3]

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

# Determine bucket owner account ID - use provided value or default to current account

# Topic variables
topic_name = split(":", var.topic_arn)[5]
topic_region = split(":", var.topic_arn)[3]
topic_account_id = split(":", var.topic_arn)[4]
is_cross_account_topic = local.topic_account_id != data.aws_caller_identity.current.account_id

# Bucket variables
bucket_account_id = var.bucket_account_id != null ? var.bucket_account_id : data.aws_caller_identity.current.account_id

# Flag for cross-account bucket access
is_cross_account = var.bucket_account_id != null && var.bucket_account_id != data.aws_caller_identity.current.account_id

# KMS variables
kms_account_id = split(":", var.kms_key_arn)[3]
need_kms_policy = var.bucket_account_id != null && var.bucket_account_id != local.kms_account_id

account_id_hash = substr(md5(local.bucket_account_id), 0, 4)
role_name = "${var.name}-${random_id.suffix.hex}-${local.account_id_hash}"

Expand Down Expand Up @@ -183,6 +190,7 @@ resource "aws_sns_topic_policy" "cloudtrail_notifications" {
}

resource "aws_sns_topic_subscription" "cloudtrail_notifications" {
count = !local.is_cross_account_topic ? 1 : 0
topic_arn = var.topic_arn
provider = aws.sns
protocol = "https"
Expand All @@ -207,9 +215,12 @@ resource "aws_cloudformation_stack_set" "cloudlogs_s3_access" {
parameters = {
RoleName = local.role_name
BucketAccountId = local.bucket_account_id
TopicAccountId = local.topic_account_id
SysdigTrustedIdentity = local.trusted_identity
SysdigExternalId = data.sysdig_secure_tenant_external_id.external_id.external_id
KmsKeyArn = var.kms_key_arn
TopicArn = var.topic_arn
IngestionUrl = local.ingestion_url
}

permission_model = "SERVICE_MANAGED"
Expand All @@ -229,7 +240,8 @@ resource "aws_cloudformation_stack_set" "cloudlogs_s3_access" {
tags = var.tags
}

resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access" {
# StackSet instance for the bucket account
resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access_bucket" {
count = local.is_cross_account ? 1 : 0

stack_set_name = aws_cloudformation_stack_set.cloudlogs_s3_access[0].name
Expand All @@ -249,6 +261,27 @@ resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access" {
}
}

# StackSet instance for the topic account
resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access_topic" {
count = local.is_cross_account ? 1 : 0

stack_set_name = aws_cloudformation_stack_set.cloudlogs_s3_access[0].name

deployment_targets {
organizational_unit_ids = var.org_units
account_filter_type = "INTERSECTION"
accounts = [local.topic_account_id]
}

region = local.topic_region

timeouts {
create = var.timeout
update = var.timeout
delete = var.timeout
}
}

#-----------------------------------------------------------------------------------------------------------------------------------------
# Call Sysdig Backend to add the cloud logs integration
#-----------------------------------------------------------------------------------------------------------------------------------------
Expand All @@ -272,6 +305,7 @@ resource "sysdig_secure_cloud_auth_account_component" "aws_cloud_logs" {

depends_on = [
aws_iam_role.cloudlogs_s3_access,
aws_cloudformation_stack_set_instance.cloudlogs_s3_access
aws_cloudformation_stack_set_instance.cloudlogs_s3_access_bucket,
aws_cloudformation_stack_set_instance.cloudlogs_s3_access_topic
]
}
2 changes: 1 addition & 1 deletion modules/integrations/cloud-logs/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ output "cloud_logs_component_id" {

output "kms_policy_instructions" {
description = "Instructions for updating KMS key policy when KMS encryption is enabled"
value = (var.kms_key_arn != null) ? templatefile(
value = (local.need_kms_policy) ? templatefile(
"${path.module}/templates/kms_policy_instructions.tpl",
{
role_arn = "arn:${data.aws_partition.current.partition}:iam::${local.bucket_account_id}:role/${local.role_name}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
"Type": "String",
"Description": "The account id that the bucket resides in"
},
"TopicAccountId": {
"Type": "String",
"Description": "The account id that the topic resides in"
},
"SysdigTrustedIdentity": {
"Type": "String",
"Description": "ARN of the Sysdig service that needs to assume the role"
Expand All @@ -21,6 +25,14 @@
"KmsKeyArn": {
"Type": "String",
"Description": "ARN of the KMS key used for encryption"
},
"TopicArn": {
"Type": "String",
"Description": "ARN of the SNS topic for CloudTrail notifications"
},
"IngestionUrl": {
"Type": "String",
"Description": "URL for Sysdig's ingestion endpoint"
}
},
"Conditions": {
Expand All @@ -34,6 +46,16 @@
}
]
},
"IsTopicAccount": {
"Fn::Equals": [
{
"Ref": "AWS::AccountId"
},
{
"Ref": "TopicAccountId"
}
]
},
"HasKMSKey": {
"Fn::Not": [
{
Expand Down Expand Up @@ -127,6 +149,19 @@
}
]
}
},
"CloudTrailSNSSubscription": {
"Type": "AWS::SNS::Subscription",
"Condition": "IsTopicAccount",
"Properties": {
"TopicArn": {
"Ref": "TopicArn"
},
"Protocol": "https",
"Endpoint": {
"Ref": "IngestionUrl"
}
}
}
},
"Outputs": {
Expand Down