From f054c4ed3d2ad215c10c8fd05ebf858a16946c4e Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Fri, 8 Feb 2019 12:21:06 +0100 Subject: [PATCH 1/6] Refactor: method and variable names Make the lifecycle method and variable names more generic, since these do not only apply to logging target buckets. Signed-off-by: Christian Berg --- sevenseconds/config/s3.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sevenseconds/config/s3.py b/sevenseconds/config/s3.py index dd84737..275a104 100644 --- a/sevenseconds/config/s3.py +++ b/sevenseconds/config/s3.py @@ -32,7 +32,7 @@ def configure_s3_buckets(account: object): else: logging_bucket = create_logging_target(s3, logging_target, region) enable_logging(bucket, logging_bucket) - configure_log_lifecycle(s3, lifecycle_config, logging_target) + configure_bucket_lifecycle(s3, lifecycle_config, logging_target) def create_logging_target(s3: object, logging_target: str, region: str): @@ -58,10 +58,10 @@ def enable_logging(bucket: object, logging_bucket: object): ) -def configure_log_lifecycle(s3: object, lifecycle_config: dict, logging_target: str): - with ActionOnExit('Check lifecycle for logging target {}'.format(logging_target)) as act: +def configure_bucket_lifecycle(s3: object, lifecycle_config: dict, bucket: str): + with ActionOnExit('Check lifecycle for bucket {}'.format(bucket)) as act: if lifecycle_config: - logging_lifecycle = s3.BucketLifecycle(logging_target) + logging_lifecycle = s3.BucketLifecycle(bucket) logging_lifecycle.put(LifecycleConfiguration=lifecycle_config) else: act.warning('skip') From 08594ce39917dbfa64570a919edeaa4f2e2076f6 Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Fri, 8 Feb 2019 12:24:38 +0100 Subject: [PATCH 2/6] Refactor: variable name Change variable name to differentiate the lifecycle config for the logging target from the lifecycle config for the main bucket (to be added next). Signed-off-by: Christian Berg --- sevenseconds/config/s3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sevenseconds/config/s3.py b/sevenseconds/config/s3.py index 275a104..df99e80 100644 --- a/sevenseconds/config/s3.py +++ b/sevenseconds/config/s3.py @@ -21,7 +21,7 @@ def configure_s3_buckets(account: object): bucket.Policy().put(Policy=policy_json) logging_target = config.get('logging_target', None) - lifecycle_config = config.get('logging_lifecycle_configuration') + logging_lifecycle_config = config.get('logging_lifecycle_configuration') if logging_target is not None: logging_enabled = bucket.Logging().logging_enabled logging_target = logging_target.format(account_id=account.id, region=region) @@ -32,7 +32,7 @@ def configure_s3_buckets(account: object): else: logging_bucket = create_logging_target(s3, logging_target, region) enable_logging(bucket, logging_bucket) - configure_bucket_lifecycle(s3, lifecycle_config, logging_target) + configure_bucket_lifecycle(s3, logging_lifecycle_config, logging_target) def create_logging_target(s3: object, logging_target: str, region: str): From 652a2c6423a8566a770fb9c319d718a2c5738378 Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Fri, 8 Feb 2019 12:28:53 +0100 Subject: [PATCH 3/6] Set lifecycle configuration for S3 buckets If a lifecycle_configuration definition is given for an S3 bucket (not just for a logging target bucket), apply it. Signed-off-by: Christian Berg --- sevenseconds/config/s3.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sevenseconds/config/s3.py b/sevenseconds/config/s3.py index df99e80..f2c1374 100644 --- a/sevenseconds/config/s3.py +++ b/sevenseconds/config/s3.py @@ -20,6 +20,10 @@ def configure_s3_buckets(account: object): policy_json = json.dumps(policy).replace('{bucket_name}', bucket_name) bucket.Policy().put(Policy=policy_json) + main_lifecycle_config = config.get('lifecycle_configuration') + if main_lifecycle_config is not None: + configure_bucket_lifecycle(s3, main_lifecycle_config, bucket_name) + logging_target = config.get('logging_target', None) logging_lifecycle_config = config.get('logging_lifecycle_configuration') if logging_target is not None: From 93d33ee3cb820496b534b867ab5c5eb8d5162b12 Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Fri, 8 Feb 2019 23:38:38 +0100 Subject: [PATCH 4/6] Add support for bucket server-side encryption Signed-off-by: Christian Berg --- sevenseconds/config/s3.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sevenseconds/config/s3.py b/sevenseconds/config/s3.py index f2c1374..4daf75a 100644 --- a/sevenseconds/config/s3.py +++ b/sevenseconds/config/s3.py @@ -24,6 +24,12 @@ def configure_s3_buckets(account: object): if main_lifecycle_config is not None: configure_bucket_lifecycle(s3, main_lifecycle_config, bucket_name) + encryption_config = config.get('encryption_config') + if encryption_config is not None: + s3.meta.client.put_bucket_encryption( + Bucket=bucket_name, + ServerSideEncryptionConfiguration=encryption_config) + logging_target = config.get('logging_target', None) logging_lifecycle_config = config.get('logging_lifecycle_configuration') if logging_target is not None: From f3ff9b901cb83b57a6a693bab2f8bd1660cc082c Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Sat, 9 Feb 2019 00:10:55 +0100 Subject: [PATCH 5/6] Add support for tagging buckets Signed-off-by: Christian Berg --- sevenseconds/config/s3.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sevenseconds/config/s3.py b/sevenseconds/config/s3.py index 4daf75a..18531d3 100644 --- a/sevenseconds/config/s3.py +++ b/sevenseconds/config/s3.py @@ -30,6 +30,13 @@ def configure_s3_buckets(account: object): Bucket=bucket_name, ServerSideEncryptionConfiguration=encryption_config) + tags = config.get('tags') + if tags is not None: + tag_set = [] + for k, v in tags.items(): + tag_set.append({'Key': k, 'Value': v}) + bucket.Tagging().put(Tagging={'TagSet': tag_set}) + logging_target = config.get('logging_target', None) logging_lifecycle_config = config.get('logging_lifecycle_configuration') if logging_target is not None: From cbba324bb326eb807869d29eaff509b0879b4a8b Mon Sep 17 00:00:00 2001 From: Christian Berg Date: Sat, 9 Feb 2019 00:55:11 +0100 Subject: [PATCH 6/6] Add test for S3 bucket configuration Signed-off-by: Christian Berg --- tests/test_aws.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_aws.py b/tests/test_aws.py index 34314d5..902a5ce 100644 --- a/tests/test_aws.py +++ b/tests/test_aws.py @@ -2,6 +2,7 @@ from unittest.mock import MagicMock from sevenseconds.helper.aws import get_account_id, get_az_names from sevenseconds.config.cloudtrail import configure_cloudtrail +from sevenseconds.config.s3 import configure_s3_buckets from datetime import datetime import botocore.exceptions @@ -129,5 +130,37 @@ def get_trail_status(Name): configure_cloudtrail(account) +def test_configure_s3_buckets(): + config = { + 's3_buckets': { + 'bucket-1': { + 'name': 'bucket-1', + 'regions': ['eu-central-1'], + 'lifecycle_configuration': {'Rules': [{'x': 'y'}]}, + 'encryption_config': {'Rules': [{'a': 'b'}]}, + 'tags': {'foo': 'bar', 'bee': 'baz'} + } + } + } + account = MagicMock(config=config) + s3 = account.session.resource('s3', 'eu-central-1') + bucket = s3.Bucket('bucket-1') + bucket.creation_date = None + + configure_s3_buckets(account) + + bucket.create.assert_called_once() + s3.BucketLifecycle('bucket-1').put.assert_called_once_with( + LifecycleConfiguration={'Rules': [{'x': 'y'}]}) + s3.meta.client.put_bucket_encryption.assert_called_once_with( + Bucket='bucket-1', + ServerSideEncryptionConfiguration={'Rules': [{'a': 'b'}]}) + bucket.Tagging().put.assert_called_once_with( + Tagging={'TagSet': [ + {'Key': 'foo', 'Value': 'bar'}, + {'Key': 'bee', 'Value': 'baz'} + ]}) + + if __name__ == '__main__': pytest.main()