in security/guardduty/index.py [0:0]
def create_s3_destination(sts_session):
"""
Create the s3 publishing destination for GuardDuty in the Control Tower
central logging account. GuardDuty findings are encrypted using
the KMS key in the GuardDuty master account.
:param sts_session: STS sesion of the GuardDuty master account
:return: properties for the GuardDuty publishing destination
"""
cloud_trail_client = sts_session.client('cloudtrail')
cloud_trail_response = cloud_trail_client.describe_trails(
trailNameList=[
'aws-controltower-BaselineCloudTrail',
]
)
logger.debug(cloud_trail_response)
trail_bucket_name = cloud_trail_response['trailList'][0]['S3BucketName']
bucket_name = trail_bucket_name.replace('logs', 'guardduty')
bucket_prefix = cloud_trail_response['trailList'][0]['S3KeyPrefix']
bucket_region = cloud_trail_response['trailList'][0]['HomeRegion']
bucket_account = trail_bucket_name.split('-')[3]
logger.debug(f'trail_bucket_name is {trail_bucket_name}')
logger.debug(f'bucket_name is {bucket_name}')
logger.debug(f'bucket_prefix is {bucket_prefix}')
logger.debug(f'bucket_region is {bucket_region}')
logger.debug(f'bucket_account is {bucket_account}')
log_account_session = assume_role(bucket_account, role_to_assume)
# Create s3 bucket in centralized log account of Control Tower
s3_client = log_account_session.client('s3')
# Only these regions are allowed in LocationConstraint
# see documentation under S3.Client.create_bucket API
allowed_regions = [
'af-south-1',
'ap-east-1',
'ap-northeast-1',
'ap-northeast-2',
'ap-northeast-3',
'ap-south-1',
'ap-southeast-1',
'ap-southeast-2',
'ca-central-1',
'cn-north-1',
'cn-northwest-1',
'eu-central-1',
'eu-north-1',
'eu-south-1',
'eu-west-1',
'eu-west-2',
'eu-west-3',
'me-south-1',
'sa-east-1',
'us-east-2',
'us-gov-east-1',
'us-gov-west-1',
'us-west-1',
'us-west-2'
]
# KMS key must be in the same region as the s3 bucket,
# so we create bucket and key together.
kms_key_arn = ''
try:
if bucket_region in allowed_regions:
kms_key_arn = create_kms_key(sts_session, bucket_region)
logger.info('Creating Destination S3 Bucket if none exists')
s3_client.create_bucket(
Bucket=bucket_name,
CreateBucketConfiguration={
'LocationConstraint': bucket_region
}
)
elif bucket_region.startswith('eu'):
kms_key_arn = create_kms_key(sts_session, bucket_region)
logger.info('Creating Destination S3 Bucket if none exists')
s3_client.create_bucket(
Bucket=bucket_name,
CreateBucketConfiguration={
'LocationConstraint': 'EU'
}
)
else:
# Bucket will be created in us-east-1
kms_key_arn = create_kms_key(sts_session, 'us-east-1')
logger.info('Creating Destination S3 Bucket if none exists')
s3_client.create_bucket(Bucket=bucket_name)
except Exception as e:
logger.info(f'Bucket {bucket_name} already created.')
logger.error(f'Skipping creating bucket {bucket_name}', exc_info=True)
bucket_policy = {
'Version': '2012-10-17',
'Statement': [
{
'Sid': 'AWSBucketPermissionsCheck',
'Effect': 'Allow',
'Principal': {
'Service': 'guardduty.amazonaws.com'
},
'Action': [
's3:GetBucketAcl',
's3:ListBucket',
's3:GetBucketLocation'
],
'Resource': f'arn:aws:s3:::{bucket_name}'
},
{
'Sid': 'AWSBucketDelivery',
'Effect': 'Allow',
'Principal': {
'Service': 'guardduty.amazonaws.com'
},
'Action': 's3:PutObject',
'Resource': f'arn:aws:s3:::{bucket_name}/*'
},
{
'Sid': 'Deny unencrypted object uploads. This is optional',
'Effect': 'Deny',
'Principal': {
'Service': 'guardduty.amazonaws.com'
},
'Action': 's3:PutObject',
'Resource': f'arn:aws:s3:::{bucket_name}/*',
'Condition': {
'StringNotEquals': {
's3:x-amz-server-side-encryption': 'aws:kms'
}
}
},
{
'Sid': 'Deny incorrect encryption header. This is optional',
'Effect': 'Deny',
'Principal': {
'Service': 'guardduty.amazonaws.com'
},
'Action': 's3:PutObject',
'Resource': f'arn:aws:s3:::{bucket_name}/*',
'Condition': {
'StringNotEquals': {
's3:x-amz-server-side-encryption-aws-kms-key-id': kms_key_arn
}
}
},
{
'Sid': 'Deny non-HTTPS access',
'Effect': 'Deny',
'Principal': '*',
'Action': 's3:*',
'Resource': f'arn:aws:s3:::{bucket_name}/*',
'Condition': {
'Bool': {
'aws:SecureTransport': 'false'
}
}
}
]
}
# Convert the policy from JSON dict to string
bucket_policy = json.dumps(bucket_policy)
s3_client.put_bucket_policy(Bucket=bucket_name, Policy=bucket_policy)
s3_client.put_bucket_encryption(
Bucket=bucket_name,
ServerSideEncryptionConfiguration={
'Rules': [
{
'ApplyServerSideEncryptionByDefault': {
'SSEAlgorithm': 'AES256'
}
},
]
}
)
destination_properties = {
'DestinationArn': f'arn:aws:s3:::{bucket_name}',
'KmsKeyArn': kms_key_arn
}
return destination_properties