From 48ae47273e8944a42889e36c80ff0d1e78cdffd4 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Thu, 27 Apr 2023 18:00:58 +0530 Subject: [PATCH 01/10] Enable Integrations-CloudTrail,GuardDuty,Listener,Role --- .gitmodules | 6 + .taskcat.yml | 47 ++- docs/.gitkeep | 0 images/.gitkeep | 0 lambda_functions/source/.gitkeep | 0 scripts/cleanup_config.json | 70 ++++ scripts/cleanup_config.py | 331 ++++++++++++++++++ scripts/sample_userdata.sh | 1 - submodules/cfn-abi-amazon-guardduty | 1 + submodules/cfn-abi-aws-cloudtrail | 1 + templates/abi-enable-qradar-integration.yaml | 159 +++++++++ .../enable-cloudtrail-integrations.yaml | 120 +++++++ .../enable-guardduty-integrations.yaml | 116 ++++++ .../enable-sqs-s3-integrations.yaml | 286 +++++++++++++++ .../enable-integrations/setup-iam-role.yaml | 59 ++++ templates/sample-workload.template.yaml | 97 ----- templates/scripts/.gitkeep | 0 templates/scripts/sample_userdata.sh | 1 - 18 files changed, 1169 insertions(+), 126 deletions(-) create mode 100644 .gitmodules create mode 100644 docs/.gitkeep create mode 100644 images/.gitkeep create mode 100644 lambda_functions/source/.gitkeep create mode 100644 scripts/cleanup_config.json create mode 100644 scripts/cleanup_config.py delete mode 100644 scripts/sample_userdata.sh create mode 160000 submodules/cfn-abi-amazon-guardduty create mode 160000 submodules/cfn-abi-aws-cloudtrail create mode 100644 templates/abi-enable-qradar-integration.yaml create mode 100644 templates/enable-integrations/enable-cloudtrail-integrations.yaml create mode 100644 templates/enable-integrations/enable-guardduty-integrations.yaml create mode 100644 templates/enable-integrations/enable-sqs-s3-integrations.yaml create mode 100644 templates/enable-integrations/setup-iam-role.yaml delete mode 100644 templates/sample-workload.template.yaml create mode 100644 templates/scripts/.gitkeep delete mode 100644 templates/scripts/sample_userdata.sh diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..eebf747 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "submodules/cfn-abi-amazon-guardduty"] + path = submodules/cfn-abi-amazon-guardduty + url = https://github.com/aws-ia/cfn-abi-amazon-guardduty +[submodule "submodules/cfn-abi-aws-cloudtrail"] + path = submodules/cfn-abi-aws-cloudtrail + url = https://github.com/aws-ia/cfn-abi-aws-cloudtrail diff --git a/.taskcat.yml b/.taskcat.yml index 1d06399..28667b5 100644 --- a/.taskcat.yml +++ b/.taskcat.yml @@ -1,33 +1,26 @@ project: - name: update-me-to-project-repo-name - owner: quickstart@amazon.com + name: cfn-abi-ibmsecurity-qradar + owner: durgadas@ibm.com package_lambda: false + shorten_stack_name: true + s3_regional_buckets: false regions: - - ap-northeast-1 - - ap-northeast-2 - - ap-southeast-1 - - ap-southeast-2 - - eu-central-1 - - eu-west-1 - - sa-east-1 - - us-east-1 - - us-west-1 - - us-west-2 + - us-east-1 + tests: - sample: + launch-qradar-main: parameters: - Param1: 'Inputs to Stack' - # Examples: of other taskcat dynamic input parameters for more into see http://taskcat.io - # - # AvailabilityZones: $[taskcat_genaz_3] - # ByteValue: 1 - # PasswordA: $[taskcat_genpass_8A] - # PasswordB: $[taskcat_genpass_32S] - # RandomNumber: $[taskcat_random-numbers] - # RandomString: $[taskcat_random-string] - # StackName: TestStack - # UUID: $[taskcat_genuuid] - # + pSRASourceS3BucketName: $[taskcat_autobucket] + pSRAS3BucketRegion: $[taskcat_current_region] + pSRAStagingS3KeyPrefix: $[taskcat_project_name] regions: - - us-east-1 - template: templates/sample-workload.template.yaml + - us-east-1 + template: templates/abi-enable-qradar-integration.yaml + launch-sqs: + parameters: + pBucketName: test-sqs-integration-bucket + pBucketArn: arn:aws:s3:::test-sqs-integration-bucket + pQueueName: test-sqs-queue + regions: + - us-east-1 + template: templates/enable-integrations/enable-sqs-s3-integrations.yaml diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/lambda_functions/source/.gitkeep b/lambda_functions/source/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/scripts/cleanup_config.json b/scripts/cleanup_config.json new file mode 100644 index 0000000..bbd6386 --- /dev/null +++ b/scripts/cleanup_config.json @@ -0,0 +1,70 @@ +[ + { + "Type": "S3_BUCKET", + "Filter": "sra-guardduty-org-delivery-", + "Account": "log_account" + }, + { + "Type": "S3_BUCKET", + "Filter": "cfn-abi-amazon-guardduty-" + }, + { + "Type": "S3_BUCKET", + "Filter": "sra-gd-staging-" + }, + { + "Type": "S3_BUCKET", + "Filter": "tcat-" + }, + { + "Type": "SSM_PARAMETER", + "Filter": "/sra/gd/" + }, + { + "Type": "STACK", + "Filter": "tCaT-enable-cloudtrail-ssm-" + }, + { + "Type": "STACK", + "Filter": "tCaT-stage-ctrail-content-local-" + }, + { + "Type": "STACK", + "Filter": "org-level-trail-dataevent-only" + }, + { + "Type": "STACK", + "Filter": "org-level-trail-with-mgmt-events" + }, + { + "Type": "S3_BUCKET", + "Filter": "sra-cloudtrail-staging-" + }, + { + "Type": "S3_BUCKET", + "Filter": "sra-org-trail-logs-", + "Account": "log_account" + }, + { + "Type": "S3_BUCKET", + "Filter": "cfn-abi-aws-cloudtrail-" + }, + { + "Type": "SSM_PARAMETER", + "Filter": "/sra/ctrail/" + }, + { + "Type": "LOG_GROUP", + "Filter": "sra/sra-org-trail" + }, + { + "Type": "LOG_GROUP", + "Filter": "/aws/lambda/sra-ct-s3", + "Account": "log_account" + }, + { + "Type": "LOG_GROUP", + "Filter": "/aws/lambda/sra-gd-s3", + "Account": "log_account" + } +] diff --git a/scripts/cleanup_config.py b/scripts/cleanup_config.py new file mode 100644 index 0000000..4241b1e --- /dev/null +++ b/scripts/cleanup_config.py @@ -0,0 +1,331 @@ +''' +Delete all resources created during ABI module testing +''' +from time import sleep +import json +import logging +import argparse + +import boto3 + +LOGGER = logging.getLogger() +LOGGER.setLevel(logging.INFO) + +SESSION = boto3.session.Session() +print('Region: %s', SESSION.region_name) + +CF = SESSION.client('cloudformation') +SSM = SESSION.client('ssm') +S3 = SESSION.client('s3') +STS = SESSION.client('sts') + +STACKSTATUS = [ 'ROLLBACK_FAILED', 'ROLLBACK_COMPLETE', 'DELETE_FAILED', 'DELETE_COMPLETE'] + +def list_stacksets(): + '''List all stacksets in the account''' + response = CF.list_stack_sets() + stacksets = response['Summaries'] + while response.get('NextToken'): + response = CF.list_stack_sets(NextToken=response['NextToken']) + stacksets.extend(response['Summaries']) + return stacksets + +def list_stackset_names(filters=None): + '''List all stackset names in the account''' + cf_info = list_stacksets() + cf_names = [] + for cfn in cf_info: + if cfn['Status'] != 'DELETED': + ss_name = cfn['StackSetName'] + if filters: + if ss_name.startswith(filters): + cf_names += [ss_name] + else: + cf_names += [ss_name] + + return cf_names + +def list_stackset_instances(stackset_name): + '''List all stackset instances in the account''' + response = CF.list_stack_instances(StackSetName=stackset_name) + stackinstances = response['Summaries'] + while response.get('NextToken'): + response = CF.list_stack_instances(StackSetName=stackset_name, + NextToken=response['NextToken']) + stackinstances.extend(response['Summaries']) + return stackinstances + +def delete_stack_instances(stackset_name, retain_stacks=False): + '''Delete all stackset instances in the account''' + stackinstances = list_stackset_instances(stackset_name) + for stackinstance in stackinstances: + CF.delete_stack_instances(StackSetName=stackset_name, + Regions=[stackinstance['Region']], + RetainStacks=retain_stacks) + +def si_account_list(stackset_name): + '''List all stackset instance accounts''' + stackinstances = list_stackset_instances(stackset_name) + stackinstance_names = [] + for stackinstance in stackinstances: + stackinstance_names += [stackinstance['Account']] + return stackinstance_names + +def si_region_list(stackset_name): + '''List all stackset instance regions''' + stackinstances = list_stackset_instances(stackset_name) + stackinstance_regions = [] + for stackinstance in stackinstances: + stackinstance_regions += [stackinstance['Region']] + return stackinstance_regions + +def delete_all_stackinstances(stackset_name): + '''Delete a stackset''' + response = None + account_list = list(dict.fromkeys(si_account_list(stackset_name))) + region_list = list(dict.fromkeys(si_region_list(stackset_name))) + if len(account_list) != 0 and len(region_list) != 0: + response = CF.delete_stack_instances(StackSetName=stackset_name, + Regions=region_list, + Accounts=account_list, + RetainStacks=False) + loop = 1 + while len(list_stackset_instances(stackset_name)) > 0 and loop < 30: + sleep(10) + loop += 1 + + return response + +def delete_stacksets(filters): + '''Delete all stacksets created by CfCT solution in the account''' + cf_names = list_stackset_names(filters) + for cf_name in cf_names: + op_info = delete_all_stackinstances(cf_name) + op_id = op_info['OperationId'] + result = CF.describe_stack_set_operation(StackSetName=cf_name, + OperationId=op_id) + op_status = result['StackSetOperation']['Status'] + while op_status != 'SUCCEEDED': + sleep(10) + result = CF.describe_stack_set_operation(StackSetName=cf_name, + OperationId=op_id) + op_status = result['StackSetOperation']['Status'] + + CF.delete_stack_set(StackSetName=cf_name) + +def list_all_stacks(): + '''List all stacks in the account''' + response = CF.list_stacks() + stacks = response['StackSummaries'] + while response.get('NextToken'): + response = CF.list_stacks(NextToken=response['NextToken']) + stacks.extend(response['StackSummaries']) + return stacks + +def list_stack_status_by_name(stack_name): + '''List stack status by stack name''' + stacks = list_all_stacks() + output = None + for stack in stacks: + if stack['StackName'] == stack_name: + output = stack['StackStatus'] + return output + +def is_nested_stack(stack_name): + '''Check if stack is a nested stack''' + stack = CF.describe_stacks(StackName=stack_name)['Stacks'][0] + result = False + if 'ParentId' in stack: + result = True + return result + +def delete_stack(filters='tCaT-'): + '''Delete all stacks created by CfCT solution in the account''' + stacks = list_all_stacks() + for stack in stacks: + stack_name = stack['StackName'] + stack_status = stack['StackStatus'] + if stack_name.startswith(filters) and stack_status != 'DELETE_COMPLETE': + if not is_nested_stack(stack_name): + print('Deleting stack: %s', stack_name) + CF.delete_stack(StackName=stack_name) + wait = 1 + while list_stack_status_by_name(stack_name) not in STACKSTATUS and wait < 60: + print('Wait: %s, Stack: %s', stack_name, wait) + sleep(10) + wait += 1 + +def delete_all_objects_from_s3_bucket(bucket_name, account=None): + '''Delete all objects from an S3 bucket''' + if account: + session = establish_remote_session(account) + sss = session.resource('s3') + else: + sss = boto3.resource('s3') + + bucket = sss.Bucket(bucket_name) + + print('Deleting all objects from bucket: %s', bucket_name) + bucket.object_versions.delete() + bucket.objects.all().delete() + +def delete_s3_buckets(filters='sra-staging-', account=None): + '''Delete all S3 buckets created by CfCT solution in the account''' + if account: + session = establish_remote_session(account) + sss = session.client('s3') + else: + sss = boto3.client('s3') + + response = sss.list_buckets() + buckets = response['Buckets'] + while response.get('NextToken'): + response = sss.list_buckets(NextToken=response['NextToken']) + buckets.extend(response['Buckets']) + print(buckets) + for bucket in buckets: + if bucket['Name'].startswith(filters): + print(filters) + try: + delete_all_objects_from_s3_bucket(bucket['Name'], account) + print('Deleting bucket: %s', bucket['Name']) + sss.delete_bucket(Bucket=bucket['Name']) + except Exception as exe: + if exe.response['Error']['Code'] == 'NoSuchBucket': + print('S3 bucket deletion issue. Skipping: %s', bucket['Name']) + else: + raise exe + +def list_all_parameters(): + ''''List all parameters in the account''' + response = SSM.describe_parameters() + parameters = response['Parameters'] + while response.get('NextToken'): + response = SSM.describe_parameters(NextToken=response['NextToken']) + parameters.extend(response['Parameters']) + return parameters + +def delete_parameters(filters='/sra/'): + '''Delete all parameters created by CfCT solution in the account''' + parameters = list_all_parameters() + for parameter in parameters: + if parameter['Name'].startswith(filters): + SSM.delete_parameter(Name=parameter['Name']) + +def get_temp_credentials(aws_account, role_name='AWSControlTowerExecution'): + ''' + Get temporary credentials from STS + ''' + role_arn = 'arn:aws:iam::' + aws_account + ':role/' + role_name + response = STS.assume_role( + RoleArn=role_arn, + RoleSessionName=str(aws_account + '-' + role_name), + DurationSeconds=3600 + ) + return response['Credentials'] + +def establish_remote_session(account): + ''' + Establish remote session + ''' + + sts_creds = get_temp_credentials(account) + return boto3.Session( + aws_access_key_id=sts_creds['AccessKeyId'], + aws_secret_access_key=sts_creds['SecretAccessKey'], + aws_session_token=sts_creds['SessionToken'] + ) + +def get_log_archive_account(parameter_name='/sra/gd/control-tower/log-archive-account-id'): + ''' + Get log archive account ID + ''' + response = SSM.get_parameter(Name=parameter_name) + return response['Parameter']['Value'] + +def get_account_id(filters='Log Archive'): + ''' + Get log account ID + ''' + acct_id = None + org = boto3.client('organizations') + accounts = org.list_accounts()['Accounts'] + for account in accounts: + if account['Name'] == filters: + acct_id = account['Id'] + return acct_id + +def list_cw_lognames(account=None): + ''' + List all CloudWatch logs + ''' + if account: + session = establish_remote_session(account) + cwlogs = session.client('logs') + else: + cwlogs = boto3.client('logs') + response = cwlogs.describe_log_groups() + log_groups = response['logGroups'] + result = [] + while response.get('nextToken'): + response = cwlogs.describe_log_groups(nextToken=response['nextToken']) + log_groups.extend(response['logGroups']) + + for log in log_groups: + result.append(log['logGroupName']) + + return result + +def delete_cw_logs(filters='sra/sra-org-trail',account=None): + ''' + Delete the pre-req data created during testing + ''' + if account: + session = establish_remote_session(account) + cwlogs = session.client('logs') + else: + cwlogs = boto3.client('logs') + log_groups = list_cw_lognames(account) + for log_group_name in log_groups: + if log_group_name.startswith(filters): + print('Deleting log group: %s', log_group_name) + cwlogs.delete_log_group(logGroupName=log_group_name) + + +if __name__ == '__main__': + PARSER = argparse.ArgumentParser(prog='cleanup_config.py', + usage='%(prog)s [-C | -h]', + description='Clear the configuration.') + PARSER.add_argument("-C", "--config", default='cleanup_config.json', + help="Clear content from config") + + ACCOUNTS = {"log_account": "Log Archive", "audit": "Audit"} + ARGS = PARSER.parse_args() + + CLEAR_CFG = ARGS.config + + with open(CLEAR_CFG, encoding="utf-8") as json_file: + CONFIG = json.load(json_file) + for item in CONFIG: + if item['Type'] == 'STACK': + delete_stack(filters=item['Filter']) + elif item['Type'] == 'S3_BUCKET': + ACCOUNT_ID = None + if 'Account' in item: + if item['Account'] in ACCOUNTS: + ACCOUNT_ID = get_account_id(ACCOUNTS[item['Account']]) + print('S3 Cleanup: Account-id: %s', ACCOUNT_ID) + delete_s3_buckets(filters=item['Filter'], account=ACCOUNT_ID) + elif item['Type'] == 'SSM_PARAMETER': + delete_parameters(filters=item['Filter']) + elif item['Type'] == 'STACK_SET': + delete_stacksets(filters=item['Filter']) + elif item['Type'] == 'LOG_GROUP': + ACCOUNT_ID = None + if 'Account' in item: + if item['Account'] in ACCOUNTS: + ACCOUNT_ID = get_account_id(ACCOUNTS[item['Account']]) + print('CW Cleanup: Account-id: %s', ACCOUNT_ID) + delete_cw_logs(filters=item['Filter'],account=ACCOUNT_ID) + else: + print('Invalid type in cleanup_config.json: %s', item['Type']) diff --git a/scripts/sample_userdata.sh b/scripts/sample_userdata.sh deleted file mode 100644 index a84a81f..0000000 --- a/scripts/sample_userdata.sh +++ /dev/null @@ -1 +0,0 @@ -#UserData and or scripts should be stored here, but only for source code revision purposes cf templatess should refer to prod s3bucket allways diff --git a/submodules/cfn-abi-amazon-guardduty b/submodules/cfn-abi-amazon-guardduty new file mode 160000 index 0000000..f929ca6 --- /dev/null +++ b/submodules/cfn-abi-amazon-guardduty @@ -0,0 +1 @@ +Subproject commit f929ca65e0440f0f99ec0a19315f34d00f9aae79 diff --git a/submodules/cfn-abi-aws-cloudtrail b/submodules/cfn-abi-aws-cloudtrail new file mode 160000 index 0000000..97f9a40 --- /dev/null +++ b/submodules/cfn-abi-aws-cloudtrail @@ -0,0 +1 @@ +Subproject commit 97f9a407d2b3a7cf5d5ddf9d551d81e910f4c14d diff --git a/templates/abi-enable-qradar-integration.yaml b/templates/abi-enable-qradar-integration.yaml new file mode 100644 index 0000000..dec8448 --- /dev/null +++ b/templates/abi-enable-qradar-integration.yaml @@ -0,0 +1,159 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: QRadar Integration + +Parameters: + PrincipalArn: + Type: String + Description: ARN of the principal that can assume the role + Default: '' + pSRASourceS3BucketName: + AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$' + ConstraintDescription: Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Default: aws-abi-pilot + Description: Source bucket for all templates and artefacts that will get copied into staging bucket + Type: String + pSRAS3BucketRegion: + AllowedPattern: ^[a-z][a-z]-[a-z]*-[0-9]*$ + Type: String + Default: us-east-1 + pSRAStagingS3KeyPrefix: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Type: String + Default: cfn-abi-ibmsecurity-qradar + +Resources: + CloudTrailIntegrationStack: + Type: AWS::CloudFormation::Stack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/templates/enable-integrations/enable-cloudtrail-integrations.yaml + Parameters: + pSRAS3BucketRegion: !Ref pSRAS3BucketRegion + pSRASourceS3BucketName: !Ref pSRASourceS3BucketName + pSRAStagingS3KeyPrefix: !Ref pSRAStagingS3KeyPrefix + + GuardDutyIntegrationStack: + Type: AWS::CloudFormation::Stack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/templates/enable-integrations/enable-guardduty-integrations.yaml + Parameters: + pSRASourceS3BucketName: !Ref pSRASourceS3BucketName + pSRAStagingS3KeyPrefix: !Ref pSRAStagingS3KeyPrefix + pSRAS3BucketRegion: !Ref pSRAS3BucketRegion + pLogArchiveAccountId: + !GetAtt [CloudTrailIntegrationStack, Outputs.oLogArchiveAccountId] + + SetupIAMRoleStack: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: qradar-setup-iam-role-stack + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Description: Setup necessary IAM roles needed for the QRadar application to access the services + ExecutionRoleName: AWSControlTowerExecution + Capabilities: + - CAPABILITY_NAMED_IAM + ManagedExecution: + Active: true + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !GetAtt [ + CloudTrailIntegrationStack, + Outputs.oLogArchiveAccountId, + ] + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/templates/enable-integrations/setup-iam-role.yaml + Parameters: + - ParameterKey: PrincipalArn + ParameterValue: !Ref PrincipalArn + - ParameterKey: CloudTrailSQSArn + ParameterValue: + !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueArn] + - ParameterKey: GuardDutySQSArn + ParameterValue: + !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueArn] + - ParameterKey: CloudTrailBucket + ParameterValue: + !GetAtt [ + CloudTrailIntegrationStack, + Outputs.oOrganizationCloudTrailS3BucketArn, + ] + - ParameterKey: GuardDutyFindingsBucket + ParameterValue: + !GetAtt [ + GuardDutyIntegrationStack, + Outputs.oPublishingDestinationBucketArn, + ] + Tags: + - Key: sra-solution + Value: !Ref pSRAStagingS3KeyPrefix + +Outputs: + oCloudTrailS3BucketName: + Description: Organization CloudTrail S3 Bucket Name + Value: + !GetAtt [ + CloudTrailIntegrationStack, + Outputs.oOrganizationCloudTrailS3BucketName, + ] + oCloudTrailS3BucketArn: + Description: Organization CloudTrail S3 Bucket Arn + Value: + !GetAtt [ + CloudTrailIntegrationStack, + Outputs.oOrganizationCloudTrailS3BucketArn, + ] + oManagementAccountId: + Description: Management Account ID + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oManagementAccountId] + oLogArchiveAccountId: + Description: Log Archive Account ID + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oLogArchiveAccountId] + oAuditAccountId: + Description: Audit Account ID + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oAuditAccountId] + oGuardDutyFindingsBucketName: + Description: GuardDuty findings Bucket Name + Value: + !GetAtt [ + GuardDutyIntegrationStack, + Outputs.oPublishingDestinationBucketName, + ] + oGuardDutyFindingsBucketArn: + Description: GuardDuty findings Bucket Name + Value: + !GetAtt [ + GuardDutyIntegrationStack, + Outputs.oPublishingDestinationBucketArn, + ] + oCloudTrailSQSQueueUrl: + Description: SQS URL for the CloudTrail events + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueURL] + oCloudTrailSQSQueueName: + Description: SQS Name for the CloudTrail events + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueName] + oCloudTrailSQSQueueArn: + Description: SQS Arn for the CloudTrail events + Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueArn] + oGuardDutyFindingsSQSQueueUrl: + Description: SQS URL for the GuardDuty findings + Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueURL] + oGuardDutyFindingsSQSQueueName: + Description: SQS Name for the GuardDuty findings + Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueName] + oGuardDutyFindingsSQSQueueArn: + Description: SQS Arn for the GuardDuty findings + Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueArn] + QRadarIAMRoleArn: + Description: The ARN of the QRadar IAM role + Value: !Sub 'arn:aws:iam::${CloudTrailIntegrationStack.Outputs.oLogArchiveAccountId}:role/QRadarRole' diff --git a/templates/enable-integrations/enable-cloudtrail-integrations.yaml b/templates/enable-integrations/enable-cloudtrail-integrations.yaml new file mode 100644 index 0000000..aa03c59 --- /dev/null +++ b/templates/enable-integrations/enable-cloudtrail-integrations.yaml @@ -0,0 +1,120 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: CloudTrail Integration for QRadar + +Parameters: + pSRASourceS3BucketName: + AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$' + ConstraintDescription: Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Default: aws-abi-pilot + Description: Source bucket for all templates and artefacts that will get copied into staging bucket + Type: String + pSRAS3BucketRegion: + AllowedPattern: ^[a-z][a-z]-[a-z]*-[0-9]*$ + Type: String + Default: us-east-1 + pSRAStagingS3KeyPrefix: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Type: String + Default: cfn-abi-ibmsecurity-qradar + pCloudTrailQueueName: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Type: String + Default: qradar-cloudtrail-queue + pCloudTrailLambdaFunctionName: + AllowedPattern: '^[\w-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] + Default: sra-ct-s3 + Description: Lambda function name for CloudTrail S3 Event Notification Configuration + Type: String + pCloudTrailLambdaRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-ct-s3-lambda + Description: Lambda execution role for CloudTrail S3 Event Notification Configuration + Type: String + +Resources: + CloudTrailStack: + Type: AWS::CloudFormation::Stack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/submodules/cfn-abi-aws-cloudtrail/templates/sra-cloudtrail-enable-in-org-ssm.yaml + Parameters: + pSRAS3BucketRegion: !Ref pSRAS3BucketRegion + pEnableDataEventsOnly: 'false' + pEnableLambdaDataEvents: 'false' + pEnableS3DataEvents: 'true' + Tags: + - Key: sra-solution + Value: !Ref pSRAStagingS3KeyPrefix + + CloudTrailEventListenerStackSet: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: qradar-cloudtrail-event-stack + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Description: Enabled S3 Bucket Event Listener to Send CloudTrail Messages to SQS + ExecutionRoleName: AWSControlTowerExecution + Capabilities: + - CAPABILITY_NAMED_IAM + ManagedExecution: + Active: true + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !GetAtt [CloudTrailStack, Outputs.oLogArchiveAccountId] + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/templates/enable-integrations/enable-sqs-s3-integrations.yaml + Parameters: + - ParameterKey: pQueueName + ParameterValue: !Ref pCloudTrailQueueName + - ParameterKey: pBucketName + ParameterValue: !GetAtt + - CloudTrailStack + - Outputs.oOrganizationCloudTrailS3BucketName + - ParameterKey: pBucketArn + ParameterValue: !GetAtt + - CloudTrailStack + - Outputs.oOrganizationCloudTrailS3BucketArn + - ParameterKey: pLambdaFunctionName + ParameterValue: !Ref pCloudTrailLambdaFunctionName + - ParameterKey: pLambdaRoleName + ParameterValue: !Ref pCloudTrailLambdaRoleName + Tags: + - Key: sra-solution + Value: !Ref pSRAStagingS3KeyPrefix + +Outputs: + oOrganizationCloudTrailS3BucketName: + Description: Organization CloudTrail S3 Bucket Name + Value: + !GetAtt [CloudTrailStack, Outputs.oOrganizationCloudTrailS3BucketName] + oOrganizationCloudTrailS3BucketArn: + Description: Organization CloudTrail S3 Bucket Arn + Value: !GetAtt [CloudTrailStack, Outputs.oOrganizationCloudTrailS3BucketArn] + oManagementAccountId: + Description: Management Account ID + Value: !GetAtt [CloudTrailStack, Outputs.oManagementAccountId] + oLogArchiveAccountId: + Description: Log Archive Account ID + Value: !GetAtt [CloudTrailStack, Outputs.oLogArchiveAccountId] + oAuditAccountId: + Description: Audit Account ID + Value: !GetAtt [CloudTrailStack, Outputs.oAuditAccountId] + oCloudTrailSQSQueueURL: + Description: 'SQS URL for the CloudTrail events' + Value: !Sub 'https://sqs.${AWS::Region}.amazonaws.com/${CloudTrailStack.Outputs.oLogArchiveAccountId}/${pCloudTrailQueueName}' + oCloudTrailSQSQueueName: + Description: 'SQS Name for the CloudTrail events' + Value: !Ref pCloudTrailQueueName + oCloudTrailSQSQueueArn: + Description: 'Arn for the CloudTrail events queue' + Value: !Sub 'arn:aws:sqs:${AWS::Region}:${CloudTrailStack.Outputs.oLogArchiveAccountId}:${pCloudTrailQueueName}' diff --git a/templates/enable-integrations/enable-guardduty-integrations.yaml b/templates/enable-integrations/enable-guardduty-integrations.yaml new file mode 100644 index 0000000..1f77e1c --- /dev/null +++ b/templates/enable-integrations/enable-guardduty-integrations.yaml @@ -0,0 +1,116 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: GuardDuty Integration for QRadar + +Parameters: + pSRASourceS3BucketName: + AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$' + ConstraintDescription: Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. + Default: aws-abi-pilot + Description: Source bucket for all templates and artefacts that will get copied into staging bucket + Type: String + pSRAS3BucketRegion: + AllowedPattern: ^[a-z][a-z]-[a-z]*-[0-9]*$ + Type: String + Default: us-east-1 + pSRAStagingS3KeyPrefix: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Type: String + Default: cfn-abi-ibmsecurity-qradar + pGuardDutyQueueName: + AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$ + Type: String + Default: qradar-guardduty-queue + pLogArchiveAccountId: + AllowedPattern: '^\d{12}$' + ConstraintDescription: Must be 12 digits + Description: LogArchive Account ID + Type: String + pGuardDutyLambdaFunctionName: + AllowedPattern: '^[\w-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] + Default: sra-gd-s3 + Description: Lambda function name for GuardDuty S3 Event Notification Configuration + Type: String + pGuardDutyLambdaRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-gd-s3-lambda + Description: Lambda execution role for GuardDuty S3 Event Notification Configuration + Type: String + +Resources: + GuardDutyStack: + Type: AWS::CloudFormation::Stack + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/submodules/cfn-abi-amazon-guardduty/templates/sra-guardduty-enable-in-org-ssm.yaml + Parameters: + pSRAS3BucketRegion: !Ref pSRAS3BucketRegion + pSraTestingFlag: 'false' + pAutoEnableS3Logs: 'true' + pAutoEnableK8sLogs: 'false' + pAutoEnableMalwareProtection: 'false' + Tags: + - Key: sra-solution + Value: !Ref pSRAStagingS3KeyPrefix + + GuardDutyEventListenerStackSet: + Type: AWS::CloudFormation::StackSet + Properties: + StackSetName: qradar-guardduty-event-stack + AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole + CallAs: SELF + Description: Enabled S3 Bucket Event Listener to Send GuardDuty finding events to SQS + ExecutionRoleName: AWSControlTowerExecution + Capabilities: + - CAPABILITY_NAMED_IAM + ManagedExecution: + Active: true + OperationPreferences: + FailureTolerancePercentage: 0 + MaxConcurrentPercentage: 100 + RegionConcurrencyType: PARALLEL + PermissionModel: SELF_MANAGED + StackInstancesGroup: + - DeploymentTargets: + Accounts: + - !Ref pLogArchiveAccountId + Regions: + - !Ref AWS::Region + TemplateURL: !Sub https://${pSRASourceS3BucketName}.s3.${pSRAS3BucketRegion}.${AWS::URLSuffix}/${pSRAStagingS3KeyPrefix}/templates/enable-integrations/enable-sqs-s3-integrations.yaml + Parameters: + - ParameterKey: pQueueName + ParameterValue: !Ref pGuardDutyQueueName + - ParameterKey: pBucketName + ParameterValue: !GetAtt + - GuardDutyStack + - Outputs.oPublishingDestinationBucketName + - ParameterKey: pBucketArn + ParameterValue: !GetAtt + - GuardDutyStack + - Outputs.oPublishingDestinationBucketArn + - ParameterKey: pLambdaFunctionName + ParameterValue: !Ref pGuardDutyLambdaFunctionName + - ParameterKey: pLambdaRoleName + ParameterValue: !Ref pGuardDutyLambdaRoleName + Tags: + - Key: sra-solution + Value: !Ref pSRAStagingS3KeyPrefix + +Outputs: + oPublishingDestinationBucketName: + Description: Publishing Destination Bucket Name + Value: !GetAtt [GuardDutyStack, Outputs.oPublishingDestinationBucketName] + oPublishingDestinationBucketArn: + Description: Publishing Destination Bucket Name + Value: !GetAtt [GuardDutyStack, Outputs.oPublishingDestinationBucketArn] + oGuardDutySQSQueueURL: + Description: 'SQS URL for the GuardDuty findings' + Value: !Sub 'https://sqs.${AWS::Region}.amazonaws.com/${pLogArchiveAccountId}/${pGuardDutyQueueName}' + oGuardDutySQSQueueName: + Description: 'SQS Name for the GuardDuty findings' + Value: !Ref pGuardDutyQueueName + oGuardDutySQSQueueArn: + Description: 'Arn for the GuardDuty findings queue' + Value: !Sub 'arn:aws:sqs:${AWS::Region}:${pLogArchiveAccountId}:${pGuardDutyQueueName}' diff --git a/templates/enable-integrations/enable-sqs-s3-integrations.yaml b/templates/enable-integrations/enable-sqs-s3-integrations.yaml new file mode 100644 index 0000000..d2f4a96 --- /dev/null +++ b/templates/enable-integrations/enable-sqs-s3-integrations.yaml @@ -0,0 +1,286 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: SQS and S3 Integration for QRadar +Parameters: + pBucketName: + Type: String + pBucketArn: + Type: String + pQueueName: + Type: String + pLambdaFunctionName: + AllowedPattern: '^[\w-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] + Default: sra-qradar-s3-listener + Description: Lambda function name for updating event listener + Type: String + pLambdaRoleName: + AllowedPattern: '^[\w+=,.@-]{1,64}$' + ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. + Default: sra-qradar-s3-listener-lambda + Description: Lambda execution role for updating event listener + Type: String + +Conditions: + cUseGraviton: !Or + - !Equals [!Ref 'AWS::Region', ap-northeast-1] + - !Equals [!Ref 'AWS::Region', ap-south-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-1] + - !Equals [!Ref 'AWS::Region', ap-southeast-2] + - !Equals [!Ref 'AWS::Region', eu-central-1] + - !Equals [!Ref 'AWS::Region', eu-west-1] + - !Equals [!Ref 'AWS::Region', eu-west-2] + - !Equals [!Ref 'AWS::Region', us-east-1] + - !Equals [!Ref 'AWS::Region', us-east-2] + - !Equals [!Ref 'AWS::Region', us-west-2] + +Resources: + rKMSKey: + Type: 'AWS::KMS::Key' + Metadata: + cfn_nag: + rules_to_suppress: + - id: F76 + reason: Need wildcard else PutBucketNotificationConfiguration operation fails with invalid destination. + checkov: + skip: + - id: CKV_AWS_33 + comment: Need wildcard else PutBucketNotificationConfiguration operation fails with invalid destination. + Properties: + Description: !Sub 'KMS Key for the ${pQueueName}' + EnableKeyRotation: true + KeyPolicy: + Version: '2012-10-17' + Id: 'key-default' + Statement: + - Sid: 'Enable IAM User Permissions' + Effect: 'Allow' + Principal: + AWS: '*' + Action: + - 'kms:*' + Resource: '*' + - Sid: 'Allow use of the key for encryption' + Effect: 'Allow' + Principal: + AWS: '*' + Action: + - 'kms:Encrypt' + Resource: '*' + + rSQSQueue: + Type: AWS::SQS::Queue + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + QueueName: !Ref pQueueName + KmsMasterKeyId: !Ref rKMSKey + + QueuePolicy: + Type: AWS::SQS::QueuePolicy + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Principal: + Service: 's3.amazonaws.com' + Action: + - SQS:SendMessage + Resource: !GetAtt rSQSQueue.Arn + Condition: + ArnLike: + aws:SourceArn: !Ref pBucketArn + Queues: + - !Ref rSQSQueue + + rS3BucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref pBucketName + PolicyDocument: + Version: '2012-10-17' + Statement: + - Sid: AllowLambdaPutBucketNotification + Effect: Allow + Principal: + AWS: !GetAtt rS3NotificationListenerLambdaRole.Arn + Action: s3:PutBucketNotification + Resource: !Join + - '' + - - 'arn:aws:s3:::' + - !Ref pBucketName + + rS3NotificationListenerLambdaCustomResource: + Type: Custom::LambdaCustomResource + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Version: '1.0' + Properties: + ServiceToken: !GetAtt rS3NotificationListenerLambdaFunction.Arn + BucketName: !Ref pBucketName + NotificationConfiguration: + QueueConfigurations: + - Event: s3:ObjectCreated:* + Queue: !GetAtt rSQSQueue.Arn + - Event: s3:ObjectRemoved:* + Queue: !GetAtt rSQSQueue.Arn + + rS3NotificationListenerLambdaFunction: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W58 + reason: Lambda role provides access to CloudWatch Logs + - id: W89 + reason: Lambda does not need to communicate with VPC resources. + - id: W92 + reason: Lambda does not need reserved concurrent executions. + checkov: + skip: + - id: CKV_AWS_115 + comment: Lambda does not need reserved concurrent executions. + - id: CKV_AWS_116 + comment: DLQ not needed, as Lambda function only triggered by CloudFormation events. + - id: CKV_AWS_117 + comment: Lambda does not need to communicate with VPC resources. + - id: CKV_AWS_173 + comment: Environment variables are not sensitive. + Type: AWS::Lambda::Function + DeletionPolicy: Delete + UpdateReplacePolicy: Delete + Properties: + FunctionName: !Ref pLambdaFunctionName + Description: Update Notification Listener for the S3 buckets + Architectures: !If + - cUseGraviton + - [arm64] + - !Ref AWS::NoValue + Handler: index.lambda_handler + Role: !GetAtt rS3NotificationListenerLambdaRole.Arn + Runtime: python3.9 + Timeout: 30 + Environment: + Variables: + LOG_LEVEL: INFO + + Code: + ZipFile: | + import boto3 + import cfnresponse + import logging + + # Configure the logger + logger = logging.getLogger() + logger.setLevel(logging.INFO) + + def lambda_handler(event, context): + logger.info('Lambda function execution started') + logger.info('Received event: %s', event) + bucket_name = event['ResourceProperties']['BucketName'] + notification_configuration = event['ResourceProperties']['NotificationConfiguration'] + + logger.info('Received bucket name: %s', bucket_name) + logger.info('Received notification configuration: %s', notification_configuration) + + try: + updated_notification_configuration = { + 'QueueConfigurations': [ + { + 'QueueArn': notification_configuration['QueueConfigurations'][0]['Queue'], + 'Events': [notification_configuration['QueueConfigurations'][0]['Event']] + }, + { + 'QueueArn': notification_configuration['QueueConfigurations'][1]['Queue'], + 'Events': [notification_configuration['QueueConfigurations'][1]['Event']] + } + ] + } + s3 = boto3.client('s3') + + if event['RequestType'] == 'Delete': + logger.info('Request type is delete') + updated_notification_configuration = {} + + response = s3.put_bucket_notification_configuration( + Bucket=bucket_name, + NotificationConfiguration=updated_notification_configuration + ) + + logger.info('Bucket notification configuration updated: %s', response) + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) + except Exception as e: + logger.error('Failed to update bucket notification configuration: %s', str(e)) + if event['RequestType'] == 'Delete': + cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) + else: + cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)}) + + rS3NotificationListenerLambdaLogGroup: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W84 + reason: CloudWatch logs are for lambda used for Cloud formation only. + - id: W28 + reason: These resources need to be retained and is immutable. + checkov: + skip: + - id: CKV_AWS_158 + comment: Ensure that CloudWatch Log Group is encrypted by KMS + Type: AWS::Logs::LogGroup + DeletionPolicy: Retain + UpdateReplacePolicy: Retain + Properties: + LogGroupName: !Sub /aws/lambda/${pLambdaFunctionName} + RetentionInDays: 1 + + rS3NotificationListenerLambdaRole: + Type: AWS::IAM::Role + Metadata: + cfn_nag: + rules_to_suppress: + - id: W28 + reason: These resources need to be retained and is immutable. + Properties: + RoleName: !Ref pLambdaRoleName + Description: !Sub Role for '${pLambdaRoleName}' Lambda function + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: sts:AssumeRole + Principal: + Service: + - lambda.amazonaws.com + Policies: + - PolicyName: S3BucketNotificationFunctionPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: s3:PutBucketNotification + Resource: !Ref pBucketArn + - PolicyName: CloudWatchLogGroup + PolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: CloudWatchLogs + Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pLambdaFunctionName}:log-stream:* + +Outputs: + QueueURL: + Description: 'URL of the SQS Queue' + Value: !Ref rSQSQueue + QueueARN: + Description: 'ARN of the AmazonSQS Queue' + Value: !GetAtt rSQSQueue.Arn + QueueName: + Description: 'Name of the Amazon SQS Queue' + Value: !GetAtt rSQSQueue.QueueName diff --git a/templates/enable-integrations/setup-iam-role.yaml b/templates/enable-integrations/setup-iam-role.yaml new file mode 100644 index 0000000..187e98e --- /dev/null +++ b/templates/enable-integrations/setup-iam-role.yaml @@ -0,0 +1,59 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: Setup IAM role for QRadar +Parameters: + PrincipalArn: + Type: String + Description: ARN of the principal that can assume the role + Default: '' + + CloudTrailSQSArn: + Type: String + Description: ARN of SQS queue for the CloudTrail events. + + GuardDutySQSArn: + Type: String + Description: ARN of SQS Queue for the GuardDuty Findings. + + CloudTrailBucket: + Type: String + Description: ARN of the CloudTrail logs bucket + + GuardDutyFindingsBucket: + Type: String + Description: ARN of the GuardDuty Findings Bucket + +Conditions: + HasPrincipalArn: !Not [!Equals [!Ref PrincipalArn, '']] + +Resources: + QRadarRole: + Type: AWS::IAM::Role + Properties: + RoleName: QRadarRole + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + AWS: !If + - HasPrincipalArn + - !Sub '${PrincipalArn}' + - !Sub 'arn:aws:iam::${AWS::AccountId}:root' + Action: sts:AssumeRole + Policies: + - PolicyName: Policy1 + PolicyDocument: + Version: '2012-10-17' + Statement: + - Sid: VisualEditor0 + Effect: Allow + Action: + - sqs:DeleteMessage + - s3:GetObject + - sqs:ReceiveMessage + - sqs:GetQueueAttributes + Resource: + - !Ref CloudTrailSQSArn + - !Ref GuardDutySQSArn + - !Ref CloudTrailBucket + - !Ref GuardDutyFindingsBucket diff --git a/templates/sample-workload.template.yaml b/templates/sample-workload.template.yaml deleted file mode 100644 index 989e996..0000000 --- a/templates/sample-workload.template.yaml +++ /dev/null @@ -1,97 +0,0 @@ ---- -AWSTemplateFormatVersion: '2010-09-09' -Description: Sample Stack -Parameters: - Param1: - Description: Param1 - Type: String -Resources: - LambdaExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Service: - - lambda.amazonaws.com - Action: - - sts:AssumeRole - Path: "/" - Policies: - - PolicyName: lambda_policy - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: arn:aws:logs:*:*:* - - Effect: Allow - Action: - - cloudformation:DescribeStacks - Resource: "*" - GenID: - Type: AWS::Lambda::Function - Properties: - Code: - ZipFile: - Fn::Join: - - "\n" - - - import random - - import json - - import cfnresponse - - from cfnresponse import send, SUCCESS - - 'def handler(event, context):' - - " if event['RequestType'] == 'Delete':" - - " send(event, context, 'SUCCESS', {})" - - " return" - - " if event['RequestType'] == 'Create':" - - ' token= "%0x.%0x" % (random.SystemRandom().getrandbits(3*8), - random.SystemRandom().getrandbits(8*8))' - - " responseData = {}" - - " responseData['Data'] = token" - - " send(event, context, 'SUCCESS', responseData)" - - " return token" - Handler: index.handler - Runtime: python3.7 - Timeout: 5 - Role: - Fn::GetAtt: - - LambdaExecutionRole - - Arn - GetID: - Type: Custom::GenerateID - Version: '1.0' - Properties: - ServiceToken: - Fn::GetAtt: - - GenID - - Arn - ResponseURL: - Fn::Join: - - '' - - - http://ResponseURL - - Ref: AWS::StackId - - RequestId - StackId: - Ref: AWS::StackId - ResourceProperties: - RequestType: Create - RequestId: - Fn::Join: - - '' - - - Ref: AWS::StackId - - RequestId - LogicalResourceId: GenIDLogicalResourceId -Outputs: - ClusterID: - Value: - Fn::GetAtt: - - GetID - - Data - Param1Output: - Value: !Ref Param1 diff --git a/templates/scripts/.gitkeep b/templates/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/templates/scripts/sample_userdata.sh b/templates/scripts/sample_userdata.sh deleted file mode 100644 index a84a81f..0000000 --- a/templates/scripts/sample_userdata.sh +++ /dev/null @@ -1 +0,0 @@ -#UserData and or scripts should be stored here, but only for source code revision purposes cf templatess should refer to prod s3bucket allways From 76b91c869bac582878c4b680fd72b318e1ead684 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Fri, 12 May 2023 14:40:53 +0530 Subject: [PATCH 02/10] Remove launch-sqs created for debugging --- .taskcat.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.taskcat.yml b/.taskcat.yml index 28667b5..66cffe7 100644 --- a/.taskcat.yml +++ b/.taskcat.yml @@ -16,11 +16,3 @@ tests: regions: - us-east-1 template: templates/abi-enable-qradar-integration.yaml - launch-sqs: - parameters: - pBucketName: test-sqs-integration-bucket - pBucketArn: arn:aws:s3:::test-sqs-integration-bucket - pQueueName: test-sqs-queue - regions: - - us-east-1 - template: templates/enable-integrations/enable-sqs-s3-integrations.yaml From 95486399fd436a8aa7cf8b602443c3b920169635 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Fri, 12 May 2023 21:07:17 +0530 Subject: [PATCH 03/10] Only need ObjectCreation notification to be setup --- templates/enable-integrations/enable-sqs-s3-integrations.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/templates/enable-integrations/enable-sqs-s3-integrations.yaml b/templates/enable-integrations/enable-sqs-s3-integrations.yaml index d2f4a96..aff1a4c 100644 --- a/templates/enable-integrations/enable-sqs-s3-integrations.yaml +++ b/templates/enable-integrations/enable-sqs-s3-integrations.yaml @@ -124,8 +124,6 @@ Resources: QueueConfigurations: - Event: s3:ObjectCreated:* Queue: !GetAtt rSQSQueue.Arn - - Event: s3:ObjectRemoved:* - Queue: !GetAtt rSQSQueue.Arn rS3NotificationListenerLambdaFunction: Metadata: From 27bfcac11a03418ad1e8e9ec4b4aa4216895caf1 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Mon, 15 May 2023 11:26:25 +0530 Subject: [PATCH 04/10] Fix open policies --- .../enable-sqs-s3-integrations.yaml | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/templates/enable-integrations/enable-sqs-s3-integrations.yaml b/templates/enable-integrations/enable-sqs-s3-integrations.yaml index aff1a4c..0b97d3b 100644 --- a/templates/enable-integrations/enable-sqs-s3-integrations.yaml +++ b/templates/enable-integrations/enable-sqs-s3-integrations.yaml @@ -36,15 +36,6 @@ Conditions: Resources: rKMSKey: Type: 'AWS::KMS::Key' - Metadata: - cfn_nag: - rules_to_suppress: - - id: F76 - reason: Need wildcard else PutBucketNotificationConfiguration operation fails with invalid destination. - checkov: - skip: - - id: CKV_AWS_33 - comment: Need wildcard else PutBucketNotificationConfiguration operation fails with invalid destination. Properties: Description: !Sub 'KMS Key for the ${pQueueName}' EnableKeyRotation: true @@ -52,17 +43,27 @@ Resources: Version: '2012-10-17' Id: 'key-default' Statement: + - Sid: 'Enable IAM User Permissions for S3 to Decrypt' + Effect: 'Allow' + Principal: + Service: + - 's3.amazonaws.com' + Action: + - 'kms:*' + Resource: '*' - Sid: 'Enable IAM User Permissions' Effect: 'Allow' Principal: - AWS: '*' + AWS: + - !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root Action: - 'kms:*' Resource: '*' - Sid: 'Allow use of the key for encryption' Effect: 'Allow' Principal: - AWS: '*' + Service: + - 'sqs.amazonaws.com' Action: - 'kms:Encrypt' Resource: '*' @@ -188,10 +189,6 @@ Resources: { 'QueueArn': notification_configuration['QueueConfigurations'][0]['Queue'], 'Events': [notification_configuration['QueueConfigurations'][0]['Event']] - }, - { - 'QueueArn': notification_configuration['QueueConfigurations'][1]['Queue'], - 'Events': [notification_configuration['QueueConfigurations'][1]['Event']] } ] } From 3e88da73c858f3c2465a43a7a8eb29b29265627a Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Mon, 15 May 2023 18:53:55 +0530 Subject: [PATCH 05/10] Remove redundant bucket policy --- .../enable-sqs-s3-integrations.yaml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/templates/enable-integrations/enable-sqs-s3-integrations.yaml b/templates/enable-integrations/enable-sqs-s3-integrations.yaml index 0b97d3b..03f69e4 100644 --- a/templates/enable-integrations/enable-sqs-s3-integrations.yaml +++ b/templates/enable-integrations/enable-sqs-s3-integrations.yaml @@ -96,23 +96,6 @@ Resources: Queues: - !Ref rSQSQueue - rS3BucketPolicy: - Type: AWS::S3::BucketPolicy - Properties: - Bucket: !Ref pBucketName - PolicyDocument: - Version: '2012-10-17' - Statement: - - Sid: AllowLambdaPutBucketNotification - Effect: Allow - Principal: - AWS: !GetAtt rS3NotificationListenerLambdaRole.Arn - Action: s3:PutBucketNotification - Resource: !Join - - '' - - - 'arn:aws:s3:::' - - !Ref pBucketName - rS3NotificationListenerLambdaCustomResource: Type: Custom::LambdaCustomResource DeletionPolicy: Delete From a1619f2ff6151b706ddeadc89496796677810192 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Mon, 15 May 2023 21:13:19 +0530 Subject: [PATCH 06/10] Retain only qradar required outputs --- templates/abi-enable-qradar-integration.yaml | 53 +------------------- 1 file changed, 2 insertions(+), 51 deletions(-) diff --git a/templates/abi-enable-qradar-integration.yaml b/templates/abi-enable-qradar-integration.yaml index dec8448..082a1d3 100644 --- a/templates/abi-enable-qradar-integration.yaml +++ b/templates/abi-enable-qradar-integration.yaml @@ -99,61 +99,12 @@ Resources: Value: !Ref pSRAStagingS3KeyPrefix Outputs: - oCloudTrailS3BucketName: - Description: Organization CloudTrail S3 Bucket Name - Value: - !GetAtt [ - CloudTrailIntegrationStack, - Outputs.oOrganizationCloudTrailS3BucketName, - ] - oCloudTrailS3BucketArn: - Description: Organization CloudTrail S3 Bucket Arn - Value: - !GetAtt [ - CloudTrailIntegrationStack, - Outputs.oOrganizationCloudTrailS3BucketArn, - ] - oManagementAccountId: - Description: Management Account ID - Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oManagementAccountId] - oLogArchiveAccountId: - Description: Log Archive Account ID - Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oLogArchiveAccountId] - oAuditAccountId: - Description: Audit Account ID - Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oAuditAccountId] - oGuardDutyFindingsBucketName: - Description: GuardDuty findings Bucket Name - Value: - !GetAtt [ - GuardDutyIntegrationStack, - Outputs.oPublishingDestinationBucketName, - ] - oGuardDutyFindingsBucketArn: - Description: GuardDuty findings Bucket Name - Value: - !GetAtt [ - GuardDutyIntegrationStack, - Outputs.oPublishingDestinationBucketArn, - ] - oCloudTrailSQSQueueUrl: + QRadarCloudTrailSQSQueueUrl: Description: SQS URL for the CloudTrail events Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueURL] - oCloudTrailSQSQueueName: - Description: SQS Name for the CloudTrail events - Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueName] - oCloudTrailSQSQueueArn: - Description: SQS Arn for the CloudTrail events - Value: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueArn] - oGuardDutyFindingsSQSQueueUrl: + QRadarGuardDutyFindingsSQSQueueUrl: Description: SQS URL for the GuardDuty findings Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueURL] - oGuardDutyFindingsSQSQueueName: - Description: SQS Name for the GuardDuty findings - Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueName] - oGuardDutyFindingsSQSQueueArn: - Description: SQS Arn for the GuardDuty findings - Value: !GetAtt [GuardDutyIntegrationStack, Outputs.oGuardDutySQSQueueArn] QRadarIAMRoleArn: Description: The ARN of the QRadar IAM role Value: !Sub 'arn:aws:iam::${CloudTrailIntegrationStack.Outputs.oLogArchiveAccountId}:role/QRadarRole' From 155fa0061e03a735421f2e0a596b529d695d9675 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Mon, 15 May 2023 21:17:30 +0530 Subject: [PATCH 07/10] Add region --- templates/abi-enable-qradar-integration.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/abi-enable-qradar-integration.yaml b/templates/abi-enable-qradar-integration.yaml index 082a1d3..dde3eb1 100644 --- a/templates/abi-enable-qradar-integration.yaml +++ b/templates/abi-enable-qradar-integration.yaml @@ -108,3 +108,6 @@ Outputs: QRadarIAMRoleArn: Description: The ARN of the QRadar IAM role Value: !Sub 'arn:aws:iam::${CloudTrailIntegrationStack.Outputs.oLogArchiveAccountId}:role/QRadarRole' + QRadarRegion: + Description: AWS Region where the SQS queues and bucket resides. + Value: !Ref AWS::Region From 5a6770ce41ec470f29394330e57a1c3db1f09a14 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Tue, 16 May 2023 12:28:13 +0530 Subject: [PATCH 08/10] Add Keys permissions --- templates/enable-integrations/setup-iam-role.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/enable-integrations/setup-iam-role.yaml b/templates/enable-integrations/setup-iam-role.yaml index 187e98e..15d1975 100644 --- a/templates/enable-integrations/setup-iam-role.yaml +++ b/templates/enable-integrations/setup-iam-role.yaml @@ -52,6 +52,13 @@ Resources: - s3:GetObject - sqs:ReceiveMessage - sqs:GetQueueAttributes + - kms:Decrypt + - kms:DescribeKey + - kms:GetKeyPolicy + - kms:DescribeKey + - kms:GetPublicKey + - kms:ListKeyPolicies + - kms:ListKeys Resource: - !Ref CloudTrailSQSArn - !Ref GuardDutySQSArn From 9d5b62498f38d636cb16ebdd08bcaed945f4166b Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Wed, 17 May 2023 19:32:10 +0530 Subject: [PATCH 09/10] Add Policy for the Role --- templates/abi-enable-qradar-integration.yaml | 6 ++++ .../enable-integrations/setup-iam-role.yaml | 30 ++++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/templates/abi-enable-qradar-integration.yaml b/templates/abi-enable-qradar-integration.yaml index dde3eb1..284f994 100644 --- a/templates/abi-enable-qradar-integration.yaml +++ b/templates/abi-enable-qradar-integration.yaml @@ -76,6 +76,12 @@ Resources: Parameters: - ParameterKey: PrincipalArn ParameterValue: !Ref PrincipalArn + - ParameterKey: LogArchiveAccountId + ParameterValue: + !GetAtt [CloudTrailIntegrationStack, Outputs.oLogArchiveAccountId] + - ParameterKey: AuditAccountId + ParameterValue: + !GetAtt [CloudTrailIntegrationStack, Outputs.oAuditAccountId] - ParameterKey: CloudTrailSQSArn ParameterValue: !GetAtt [CloudTrailIntegrationStack, Outputs.oCloudTrailSQSQueueArn] diff --git a/templates/enable-integrations/setup-iam-role.yaml b/templates/enable-integrations/setup-iam-role.yaml index 15d1975..31975a2 100644 --- a/templates/enable-integrations/setup-iam-role.yaml +++ b/templates/enable-integrations/setup-iam-role.yaml @@ -10,6 +10,14 @@ Parameters: Type: String Description: ARN of SQS queue for the CloudTrail events. + LogArchiveAccountId: + Type: String + Description: AccountId for the Log Archive + + AuditAccountId: + Type: String + Description: AccountId for the Audit + GuardDutySQSArn: Type: String Description: ARN of SQS Queue for the GuardDuty Findings. @@ -41,7 +49,7 @@ Resources: - !Sub 'arn:aws:iam::${AWS::AccountId}:root' Action: sts:AssumeRole Policies: - - PolicyName: Policy1 + - PolicyName: QradarPolicy PolicyDocument: Version: '2012-10-17' Statement: @@ -50,17 +58,19 @@ Resources: Action: - sqs:DeleteMessage - s3:GetObject + - kms:Decrypt - sqs:ReceiveMessage - sqs:GetQueueAttributes - - kms:Decrypt - - kms:DescribeKey - - kms:GetKeyPolicy - - kms:DescribeKey - - kms:GetPublicKey - - kms:ListKeyPolicies - - kms:ListKeys Resource: + - !Sub arn:aws:kms:${AWS::Region}:${LogArchiveAccountId}:key/* + - !Sub arn:aws:kms:${AWS::Region}:${AuditAccountId}:key/* - !Ref CloudTrailSQSArn - !Ref GuardDutySQSArn - - !Ref CloudTrailBucket - - !Ref GuardDutyFindingsBucket + - !Join + - '' + - - !Ref CloudTrailBucket + - '/*' + - !Join + - '' + - - !Ref GuardDutyFindingsBucket + - '/*' From 788b549b0a61b7bf565f77061ea1803247e44e64 Mon Sep 17 00:00:00 2001 From: imdurgadas Date: Thu, 18 May 2023 19:45:53 +0530 Subject: [PATCH 10/10] supress the cfb_nag --- templates/enable-integrations/setup-iam-role.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/enable-integrations/setup-iam-role.yaml b/templates/enable-integrations/setup-iam-role.yaml index 31975a2..2a86316 100644 --- a/templates/enable-integrations/setup-iam-role.yaml +++ b/templates/enable-integrations/setup-iam-role.yaml @@ -35,6 +35,13 @@ Conditions: Resources: QRadarRole: + Metadata: + cfn_nag: + rules_to_suppress: + - id: W11 + reason: Allow * in resource when required + - id: W12 + reason: Allow * in policy when required Type: AWS::IAM::Role Properties: RoleName: QRadarRole