Skip to content

Commit 81717fa

Browse files
feat(cloudlogs): cross account and region support (#55)
1 parent 5e39d23 commit 81717fa

File tree

4 files changed

+90
-11
lines changed

4 files changed

+90
-11
lines changed

modules/integrations/cloud-logs/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,16 @@ The following resources will be created based on the deployment scenario:
1414
- SNS Topic and Subscription for CloudTrail notifications
1515

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

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

2528
## Important Notes for Cross-Account Access
2629

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

40+
### Cross-Region Deployments
41+
42+
This module supports deployments where the S3 bucket and SNS topic are in different regions:
43+
- The IAM role will be created in the current region but can access the S3 bucket regardless of its region
44+
- The SNS subscription will be created in the same region as the SNS topic
45+
- The StackSet will deploy to both regions as needed
46+
3747
<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
3848

3949
## Requirements

modules/integrations/cloud-logs/main.tf

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,24 @@ data "sysdig_secure_cloud_ingestion_assets" "assets" {
4646
locals {
4747
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
4848

49-
topic_name = split(":", var.topic_arn)[5]
50-
topic_region = split(":", var.topic_arn)[3]
49+
5150
routing_key = data.sysdig_secure_cloud_ingestion_assets.assets.aws.sns_routing_key
5251
ingestion_url = data.sysdig_secure_cloud_ingestion_assets.assets.aws.sns_routing_url
53-
54-
# Determine bucket owner account ID - use provided value or default to current account
52+
53+
# Topic variables
54+
topic_name = split(":", var.topic_arn)[5]
55+
topic_region = split(":", var.topic_arn)[3]
56+
topic_account_id = split(":", var.topic_arn)[4]
57+
is_cross_account_topic = local.topic_account_id != data.aws_caller_identity.current.account_id
58+
59+
# Bucket variables
5560
bucket_account_id = var.bucket_account_id != null ? var.bucket_account_id : data.aws_caller_identity.current.account_id
56-
57-
# Flag for cross-account bucket access
5861
is_cross_account = var.bucket_account_id != null && var.bucket_account_id != data.aws_caller_identity.current.account_id
5962

63+
# KMS variables
64+
kms_account_id = split(":", var.kms_key_arn)[3]
65+
need_kms_policy = var.bucket_account_id != null && var.bucket_account_id != local.kms_account_id
66+
6067
account_id_hash = substr(md5(local.bucket_account_id), 0, 4)
6168
role_name = "${var.name}-${random_id.suffix.hex}-${local.account_id_hash}"
6269

@@ -183,6 +190,7 @@ resource "aws_sns_topic_policy" "cloudtrail_notifications" {
183190
}
184191

185192
resource "aws_sns_topic_subscription" "cloudtrail_notifications" {
193+
count = !local.is_cross_account_topic ? 1 : 0
186194
topic_arn = var.topic_arn
187195
provider = aws.sns
188196
protocol = "https"
@@ -207,9 +215,12 @@ resource "aws_cloudformation_stack_set" "cloudlogs_s3_access" {
207215
parameters = {
208216
RoleName = local.role_name
209217
BucketAccountId = local.bucket_account_id
218+
TopicAccountId = local.topic_account_id
210219
SysdigTrustedIdentity = local.trusted_identity
211220
SysdigExternalId = data.sysdig_secure_tenant_external_id.external_id.external_id
212221
KmsKeyArn = var.kms_key_arn
222+
TopicArn = var.topic_arn
223+
IngestionUrl = local.ingestion_url
213224
}
214225

215226
permission_model = "SERVICE_MANAGED"
@@ -229,7 +240,8 @@ resource "aws_cloudformation_stack_set" "cloudlogs_s3_access" {
229240
tags = var.tags
230241
}
231242

232-
resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access" {
243+
# StackSet instance for the bucket account
244+
resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access_bucket" {
233245
count = local.is_cross_account ? 1 : 0
234246

235247
stack_set_name = aws_cloudformation_stack_set.cloudlogs_s3_access[0].name
@@ -249,6 +261,27 @@ resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access" {
249261
}
250262
}
251263

264+
# StackSet instance for the topic account
265+
resource "aws_cloudformation_stack_set_instance" "cloudlogs_s3_access_topic" {
266+
count = local.is_cross_account ? 1 : 0
267+
268+
stack_set_name = aws_cloudformation_stack_set.cloudlogs_s3_access[0].name
269+
270+
deployment_targets {
271+
organizational_unit_ids = var.org_units
272+
account_filter_type = "INTERSECTION"
273+
accounts = [local.topic_account_id]
274+
}
275+
276+
region = local.topic_region
277+
278+
timeouts {
279+
create = var.timeout
280+
update = var.timeout
281+
delete = var.timeout
282+
}
283+
}
284+
252285
#-----------------------------------------------------------------------------------------------------------------------------------------
253286
# Call Sysdig Backend to add the cloud logs integration
254287
#-----------------------------------------------------------------------------------------------------------------------------------------
@@ -272,6 +305,7 @@ resource "sysdig_secure_cloud_auth_account_component" "aws_cloud_logs" {
272305

273306
depends_on = [
274307
aws_iam_role.cloudlogs_s3_access,
275-
aws_cloudformation_stack_set_instance.cloudlogs_s3_access
308+
aws_cloudformation_stack_set_instance.cloudlogs_s3_access_bucket,
309+
aws_cloudformation_stack_set_instance.cloudlogs_s3_access_topic
276310
]
277311
}

modules/integrations/cloud-logs/outputs.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ output "cloud_logs_component_id" {
66

77
output "kms_policy_instructions" {
88
description = "Instructions for updating KMS key policy when KMS encryption is enabled"
9-
value = (var.kms_key_arn != null) ? templatefile(
9+
value = (local.need_kms_policy) ? templatefile(
1010
"${path.module}/templates/kms_policy_instructions.tpl",
1111
{
1212
role_arn = "arn:${data.aws_partition.current.partition}:iam::${local.bucket_account_id}:role/${local.role_name}"

modules/integrations/cloud-logs/templates/stackset_template_body.tpl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
"Type": "String",
1111
"Description": "The account id that the bucket resides in"
1212
},
13+
"TopicAccountId": {
14+
"Type": "String",
15+
"Description": "The account id that the topic resides in"
16+
},
1317
"SysdigTrustedIdentity": {
1418
"Type": "String",
1519
"Description": "ARN of the Sysdig service that needs to assume the role"
@@ -21,6 +25,14 @@
2125
"KmsKeyArn": {
2226
"Type": "String",
2327
"Description": "ARN of the KMS key used for encryption"
28+
},
29+
"TopicArn": {
30+
"Type": "String",
31+
"Description": "ARN of the SNS topic for CloudTrail notifications"
32+
},
33+
"IngestionUrl": {
34+
"Type": "String",
35+
"Description": "URL for Sysdig's ingestion endpoint"
2436
}
2537
},
2638
"Conditions": {
@@ -34,6 +46,16 @@
3446
}
3547
]
3648
},
49+
"IsTopicAccount": {
50+
"Fn::Equals": [
51+
{
52+
"Ref": "AWS::AccountId"
53+
},
54+
{
55+
"Ref": "TopicAccountId"
56+
}
57+
]
58+
},
3759
"HasKMSKey": {
3860
"Fn::Not": [
3961
{
@@ -127,6 +149,19 @@
127149
}
128150
]
129151
}
152+
},
153+
"CloudTrailSNSSubscription": {
154+
"Type": "AWS::SNS::Subscription",
155+
"Condition": "IsTopicAccount",
156+
"Properties": {
157+
"TopicArn": {
158+
"Ref": "TopicArn"
159+
},
160+
"Protocol": "https",
161+
"Endpoint": {
162+
"Ref": "IngestionUrl"
163+
}
164+
}
130165
}
131166
},
132167
"Outputs": {

0 commit comments

Comments
 (0)