diff --git a/modules/log_ingestion.s3.cft.yaml b/modules/log_ingestion.s3.cft.yaml index b88ad75..aea9660 100644 --- a/modules/log_ingestion.s3.cft.yaml +++ b/modules/log_ingestion.s3.cft.yaml @@ -1,8 +1,7 @@ AWSTemplateFormatVersion: "2010-09-09" Description: > - CloudFormation organizational template for provisioning the necessary resources - for the `cloud-logs` component and the read-only role required to interact with - the target organizational environment. + CloudFormation template for provisioning the necessary resources + for the `cloud-logs` component, allowing Sysdig to access CloudTrail logs in S3 buckets. Metadata: AWS::CloudFormation::Interface: @@ -14,9 +13,15 @@ Metadata: - ExternalID - TrustedIdentity - BucketARN + - KMSKeyARN + - KMSAccountId + - BucketAccountId + - TopicAccountId + - OrganizationalUnitIds - CreateTopic - TopicARN - Endpoint + - TopicRegion ParameterLabels: NameSuffix: @@ -27,12 +32,24 @@ Metadata: default: Trusted Identity BucketARN: default: Bucket ARN + KMSKeyARN: + default: KMS Key ARN + KMSAccountId: + default: KMS Account ID + BucketAccountId: + default: Bucket Account ID + TopicAccountId: + default: SNS Topic Account ID + OrganizationalUnitIds: + default: Organizational Unit IDs CreateTopic: default: Create SNS Topic TopicARN: default: SNS Topic ARN Endpoint: default: Sysdig Secure endpoint + TopicRegion: + default: The AWS region where the SNS topic is located Parameters: NameSuffix: @@ -50,6 +67,28 @@ Parameters: BucketARN: Type: String Description: The ARN of your S3 bucket associated with your CloudTrail trail logs. + AllowedPattern: 'arn:(aws|aws-us-gov):s3:::.*' + KMSKeyARN: + Type: String + Description: The ARN of the KMS key used to encrypt the S3 bucket. + Default: "" + KMSAccountId: + Type: String + Description: The AWS Account ID that owns the KMS key. + AllowedPattern: '^[0-9]{12}$' + BucketAccountId: + Type: String + Description: The AWS Account ID that owns the S3 bucket, if different from the current account. + AllowedPattern: '^[0-9]{12}$' + TopicAccountId: + Type: String + Description: The AWS Account ID that owns the SNS topic. + AllowedPattern: '^[0-9]{12}$' + OrganizationalUnitIds: + Type: String + Description: Comma-separated list of AWS Organizations organizational unit (OU) IDs for cross-account deployments. + Default: "r-root" + AllowedPattern: '^(ou-[a-z0-9]{4,32}-[a-z0-9]{8,32}|r-[a-z0-9]{4,32})(,\s*(ou-[a-z0-9]{4,32}-[a-z0-9]{8,32}|r-[a-z0-9]{4,32}))*$' CreateTopic: Type: String AllowedValues: @@ -63,12 +102,37 @@ Parameters: Endpoint: Type: String Description: Sysdig Secure endpoint to receive CloudTrail notifications. + TopicRegion: + Type: String + Description: The AWS region where the SNS topic is located + AllowedPattern: '^[a-zA-Z0-9-]{1,128}$' + +Conditions: + CreateSNSTopic: !Equals [ !Ref CreateTopic, "true" ] + HasKMSKey: !Not [ !Equals [ !Ref KMSKeyARN, "" ] ] + DeployStackSet: !Or [ + !Not [ !Equals [ !Ref BucketAccountId, !Ref "AWS::AccountId" ] ], + !Not [ !Equals [ !Ref TopicAccountId, !Ref "AWS::AccountId" ] ] + ] + + DeployRole: !And [ + !Equals [ !Ref BucketAccountId, !Ref "AWS::AccountId" ] , + !Equals [ DeployStackSet, "false" ] + ] + + NeedKMSPolicy: !And [ + !Not [ !Equals [ !Ref KMSKeyARN, "" ] ], + !Not [ !Equals [ !Ref KMSAccountId, !Ref BucketAccountId ] ] + ] + IsTopicAccount: !Equals [ !Ref TopicAccountId, !Ref "AWS::AccountId" ] Resources: + # Role and resources for same-account deployments CloudLogsRole: Type: "AWS::IAM::Role" + Condition: DeployRole Properties: - RoleName: !Sub sysdig-secure-cloudlogs-${NameSuffix} + RoleName: !Sub sysdig-secure-cloudlogs-${NameSuffix} AssumeRolePolicyDocument: Version: "2012-10-17" Statement: @@ -85,20 +149,29 @@ Resources: PolicyDocument: Version: "2012-10-17" Statement: - - Sid: "CloudlogsS3AccessGet" + - Sid: "CloudlogsS3Access" Effect: "Allow" Action: - "s3:Get*" - Resource: - - !Sub '${BucketARN}' - - !Sub '${BucketARN}/*' - - Sid: "CloudlogsS3AccessList" - Effect: "Allow" - Action: - "s3:List*" Resource: - !Sub '${BucketARN}' - !Sub '${BucketARN}/*' + - !If + - HasKMSKey + - Sid: "CloudlogsKMSDecrypt" + Effect: "Allow" + Action: + - "kms:Decrypt" + Resource: !Ref KMSKeyARN + - !Ref "AWS::NoValue" + Tags: + - Key: "Name" + Value: "Sysdig Secure CloudTrail Logs Access Role" + - Key: "Purpose" + Value: "Allow Sysdig to access S3 bucket for CloudTrail logs" + - Key: "product" + Value: "sysdig-secure-for-cloud" CloudTrailNotificationsTopic: Condition: CreateSNSTopic @@ -107,6 +180,7 @@ Resources: TopicName: !Select [ 5, !Split [ ":", !Ref TopicARN ] ] CloudTrailNotificationsSubscription: + Condition: IsTopicAccount Type: "AWS::SNS::Subscription" Properties: TopicArn: !If [ CreateSNSTopic, !Ref CloudTrailNotificationsTopic, !Ref TopicARN ] @@ -129,10 +203,173 @@ Resources: Action: "SNS:Publish" Resource: !Ref CloudTrailNotificationsTopic -Conditions: - CreateSNSTopic: !Equals [ !Ref CreateTopic, "true" ] + # StackSet for cross-account bucket access + BucketAccessStackSet: + Type: AWS::CloudFormation::StackSet + Condition: DeployStackSet + Properties: + StackSetName: !Sub sysdig-secure-cloudlogs-bucket-access-${NameSuffix} + Description: StackSet to configure S3 bucket and KMS permissions for Sysdig Cloud Logs integration + PermissionModel: SERVICE_MANAGED + AutoDeployment: + Enabled: false + ManagedExecution: + Active: true + Capabilities: + - "CAPABILITY_NAMED_IAM" + OperationPreferences: + MaxConcurrentPercentage: 100 + FailureTolerancePercentage: 90 + ConcurrencyMode: SOFT_FAILURE_TOLERANCE + Parameters: + - ParameterKey: NameSuffix + ParameterValue: !Ref NameSuffix + - ParameterKey: RoleName + ParameterValue: !Sub sysdig-secure-cloudlogs-${NameSuffix} + - ParameterKey: TrustedIdentity + ParameterValue: !Ref TrustedIdentity + - ParameterKey: ExternalID + ParameterValue: !Ref ExternalID + - ParameterKey: BucketARN + ParameterValue: !Ref BucketARN + - ParameterKey: KMSKeyARN + ParameterValue: !Ref KMSKeyARN + - ParameterKey: BucketAccountId + ParameterValue: !Ref BucketAccountId + - ParameterKey: TopicARN + ParameterValue: !Ref TopicARN + - ParameterKey: TopicAccountId + ParameterValue: !Ref TopicAccountId + - ParameterKey: Endpoint + ParameterValue: !Ref Endpoint + - ParameterKey: TopicRegion + ParameterValue: !Ref TopicRegion + StackInstancesGroup: + - DeploymentTargets: + OrganizationalUnitIds: !Split [",", !Ref OrganizationalUnitIds] + Accounts: [!Ref BucketAccountId] + AccountFilterType: INTERSECTION + Regions: [!Ref "AWS::Region"] + - DeploymentTargets: + OrganizationalUnitIds: !Split [",", !Ref OrganizationalUnitIds] + Accounts: [!Ref TopicAccountId] + AccountFilterType: INTERSECTION + Regions: [!Ref TopicRegion] + TemplateBody: | + AWSTemplateFormatVersion: "2010-09-09" + Description: IAM Role for S3 bucket and KMS access for Sysdig Cloud Logs integration + Parameters: + NameSuffix: + Type: String + Description: Suffix to append to the resource name identifiers + RoleName: + Type: String + Description: Name of the role to be created in the bucket account + TrustedIdentity: + Type: String + Description: ARN of the Sysdig service that needs to assume the role + ExternalID: + Type: String + Description: External ID for secure role assumption by Sysdig + BucketARN: + Type: String + Description: ARN of the S3 bucket containing CloudTrail logs + KMSKeyARN: + Type: String + Description: ARN of the KMS key used for encryption + Default: "" + BucketAccountId: + Type: String + Description: AWS Account ID that owns the S3 bucket + TopicARN: + Type: String + Description: ARN of the SNS topic + TopicAccountId: + Type: String + Description: AWS Account ID that owns the SNS topic + Endpoint: + Type: String + Description: Sysdig Secure endpoint to receive CloudTrail notifications + TopicRegion: + Type: String + Description: The AWS region where the SNS topic is located + Conditions: + IsBucketAccount: !Equals [ !Ref BucketAccountId, !Ref "AWS::AccountId" ] + IsTopicAccount: !Equals [ !Ref TopicAccountId, !Ref "AWS::AccountId" ] + HasKMSKey: !Not [ !Equals [ !Ref KMSKeyARN, "" ] ] + Resources: + S3AccessRole: + Type: AWS::IAM::Role + Condition: IsBucketAccount + Properties: + RoleName: !Ref RoleName + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: "Allow" + Principal: + AWS: !Ref TrustedIdentity + Action: "sts:AssumeRole" + Condition: + StringEquals: + "sts:ExternalId": !Ref ExternalID + Policies: + - PolicyName: !Sub "sysdig-secure-cloudlogs-policy-${AWS::AccountId}-${NameSuffix}" + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "S3BucketListAccess" + Effect: "Allow" + Action: + - "s3:ListBucket" + - "s3:GetBucketLocation" + Resource: + - !Ref BucketARN + - Sid: "S3ObjectAccess" + Effect: "Allow" + Action: + - "s3:GetObject" + Resource: + - !Sub "${BucketARN}/*" + - !If + - HasKMSKey + - Sid: "KMSDecryptAccess" + Effect: "Allow" + Action: "kms:Decrypt" + Resource: !Ref KMSKeyARN + - !Ref "AWS::NoValue" + Tags: + - Key: "Name" + Value: "Sysdig Secure CloudTrail Logs Access Role" + - Key: "Purpose" + Value: "Allow Sysdig to access S3 bucket for CloudTrail logs" + - Key: "product" + Value: "sysdig-secure-for-cloud" + CloudTrailSNSSubscription: + Type: AWS::SNS::Subscription + Condition: IsTopicAccount + Properties: + TopicArn: !Ref TopicARN + Protocol: "https" + Endpoint: !Ref Endpoint Outputs: - TopicARN: - Description: "The ARN of the SNS Topic created for CloudTrail notifications." - Value: !If [ CreateSNSTopic, !Ref CloudTrailNotificationsTopic, !Ref TopicARN ] + KMSPolicyInstructions: + Description: "Instructions for updating KMS key policy when KMS encryption is enabled" + Condition: NeedKMSPolicy + Value: !Sub | + IMPORTANT: MANUAL ACTION REQUIRED + + Please add the following statement to your KMS key policy to allow Sysdig to decrypt logs. + This is necessary when KMS encryption is enabled for your S3 bucket and the KMS key is in a different account. + Without this policy addition, Sysdig may not be able to read your encrypted logs. + + { + "Sid": "Sysdig-Decrypt", + "Effect": "Allow", + "Principal": { + "AWS": "sysdig-secure-cloudlogs-${NameSuffix}" + }, + "Action": "kms:Decrypt", + "Resource": "*" + }