From 9681d4714cdf79f462e46fc7a3deef659f830c02 Mon Sep 17 00:00:00 2001 From: abikouo Date: Mon, 29 Mar 2021 11:36:50 +0200 Subject: [PATCH 01/21] feature - add object ownership controls for s3 bucket --- plugins/modules/s3_bucket.py | 87 +++++++++++++++- tests/integration/targets/s3_bucket/inventory | 1 + .../s3_bucket/tasks/ownership_controls.yml | 98 +++++++++++++++++++ 3 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 467e42b44c4..548699895ba 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -25,7 +25,9 @@ description: - Manage S3 buckets in AWS, DigitalOcean, Ceph, Walrus, FakeS3 and StorageGRID. requirements: [ boto3 ] -author: "Rob White (@wimnat)" +author: + - Rob White (@wimnat) + - Aubin Bikouo (@abikouo) options: force: description: @@ -120,6 +122,23 @@ default: false type: bool version_added: 1.3.0 + object_ownership: + description: + - Allow bucket's ownership controls. + - BucketOwnerPreferred : Objects uploaded to the bucket change ownership to the bucket owner + if the objects are uploaded with the bucket-owner-full-control canned ACL. + - ObjectWriter: The uploading account will own the object + if the object is uploaded with the bucket-owner-full-control canned ACL. + - This option cannot be used together with a I(delete_object_ownership) definition. + choices: [ 'BucketOwnerPreferred', 'ObjectWriter' ] + type: str + delete_object_ownership: + description: + - Delete bucket's ownership controls. + - This option cannot be used together with a I(object_ownership) definition. + default: false + type: bool + version_added: 1.3.0 extends_documentation_fragment: - amazon.aws.aws @@ -202,6 +221,18 @@ name: mys3bucket state: present delete_public_access: true + +# Create a bucket with object ownership controls set to ObjectWriter +- amazon.aws.s3_bucket: + name: mys3bucket + state: present + object_ownership: ObjectWriter + +# Delete onwership controls from bucket +- amazon.aws.s3_bucket: + name: mys3bucket + state: present + delete_object_ownership: true ''' import json @@ -240,6 +271,8 @@ def create_or_update_bucket(s3_client, module, location): encryption_key_id = module.params.get("encryption_key_id") public_access = module.params.get("public_access") delete_public_access = module.params.get("delete_public_access") + delete_object_ownership = module.params.get("delete_object_ownership") + object_ownership=module.params.get("object_ownership") changed = False result = {} @@ -440,6 +473,25 @@ def create_or_update_bucket(s3_client, module, location): changed = True result['public_access_block'] = {} + # -- Bucket ownership + bucket_ownership = get_bucket_ownership_cntrl(s3_client,name) + result['object_ownership'] = bucket_ownership + if delete_object_ownership or object_ownership is not None : + if delete_object_ownership : + # delete S3 buckect ownership + if bucket_ownership != {} : + delete_bucket_ownership(s3_client,name) + changed=True + result['object_ownership']=None + else: + # update S3 bucket ownership + if bucket_ownership != object_ownership : + put_bucket_ownership(s3_client,name,object_ownership) + changed=True + result['object_ownership'] = object_ownership + + + # Module exit module.exit_json(changed=changed, name=name, **result) @@ -587,6 +639,23 @@ def delete_bucket_public_access(s3_client, bucket_name): ''' s3_client.delete_public_access_block(Bucket=bucket_name) +@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) +def delete_bucket_ownership(s3_client,bucket_name) : + ''' + Delete bucket ownership controls from S3 bucket + ''' + s3_client.delete_bucket_ownership_controls(Bucket=bucket_name) + +@AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) +def put_bucket_ownership(s3_client,bucket_name,target) : + ''' + Put bucket ownership controls for S3 bucket + ''' + s3_client.put_bucket_ownership_controls(Bucket=bucket_name, + OwnershipControls={ + 'Rules': [ { 'ObjectOwnership': target } ] + }) + def wait_policy_is_applied(module, s3_client, bucket_name, expected_policy, should_fail=True): for dummy in range(0, 12): @@ -691,6 +760,15 @@ def get_bucket_public_access(s3_client, bucket_name): except is_boto3_error_code('NoSuchPublicAccessBlockConfiguration'): return {} +def get_bucket_ownership_cntrl(s3_client,bucket_name) : + ''' + Get current bucket public access block + ''' + try: + bucket_ownership = s3_client.get_bucket_ownership_controls(Bucket=bucket_name) + return bucket_ownership['OwnershipControls']['Rules'][0]['ObjectOwnership'] + except is_boto3_error_code([ 'OwnershipControlsNotFoundError','NoSuchOwnershipControls' ]): + return None def paginated_list(s3_client, **pagination_params): pg = s3_client.get_paginator('list_objects_v2') @@ -809,7 +887,9 @@ def main(): ignore_public_acls=dict(type='bool', default=False), block_public_policy=dict(type='bool', default=False), restrict_public_buckets=dict(type='bool', default=False))), - delete_public_access=dict(type='bool', default=False) + delete_public_access=dict(type='bool', default=False), + object_ownership=dict(type='str',choices=['BucketOwnerPreferred','ObjectWriter']), + delete_object_ownership=dict(type='bool',default=False) ) required_by = dict( @@ -817,7 +897,8 @@ def main(): ) mutually_exclusive = [ - ['public_access', 'delete_public_access'] + ['public_access', 'delete_public_access'], + ['delete_object_ownership', 'object_ownership'] ] module = AnsibleAWSModule( diff --git a/tests/integration/targets/s3_bucket/inventory b/tests/integration/targets/s3_bucket/inventory index 59a2423acdd..62dcff0fbe7 100644 --- a/tests/integration/targets/s3_bucket/inventory +++ b/tests/integration/targets/s3_bucket/inventory @@ -7,6 +7,7 @@ tags encryption_kms encryption_sse public_access +ownership_controls [all:vars] ansible_connection=local diff --git a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml new file mode 100644 index 00000000000..5bc06e1e70d --- /dev/null +++ b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml @@ -0,0 +1,98 @@ +--- +- module_defaults: + group/aws: + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token | default(omit) }}" + region: "{{ aws_region }}" + block: + + # ============================================================ + + - name: 'Create a simple bucket bad value for ownership controls' + s3_bucket: + name: '{{ bucket_name }}' + state: present + object_ownership: default + ignore_errors: true + register: output + + - assert: + that: + - output.failed + + - name: 'Create bucket with object_ownership set to object_writer' + s3_bucket: + name: '{{ bucket_name }}' + state: present + ignore_errors: true + register: output + + - assert: + that: + - output.changed + - not output.object_ownership|bool + + - name: delete s3 bucket + s3_bucket: + name: '{{ bucket_name }}' + state: absent + + - name: 'create s3 bucket with object ownership controls' + s3_bucket: + name: '{{ bucket_name }}' + state: present + object_ownership: ObjectWriter + register: output + + - assert: + that: + - output.changed + - output.object_ownership + - output.object_ownership == 'ObjectWriter' + + - name: 'update s3 bucket ownership controls' + s3_bucket: + name: '{{ bucket_name }}' + state: present + object_ownership: BucketOwnerPreferred + register: output + + - assert: + that: + - output.changed + - output.object_ownership + - output.object_ownership == 'BucketOwnerPreferred' + + - name: 'test idempotency update s3 bucket ownership controls' + s3_bucket: + name: '{{ bucket_name }}' + state: present + object_ownership: BucketOwnerPreferred + register: output + + - assert: + that: + - output.changed is false + - output.object_ownership + - output.object_ownership == 'BucketOwnerPreferred' + + - name: 'delete s3 bucket ownership controls' + s3_bucket: + name: '{{ bucket_name }}' + state: present + delete_object_ownership: true + register: output + + - assert: + that: + - output.changed + - not output.object_ownership|bool + + # ============================================================ + always: + - name: Ensure all buckets are deleted + s3_bucket: + name: '{{ bucket_name }}' + state: absent + ignore_errors: yes From 90abe86a38cfdb01df1382432288cf79c9b310b1 Mon Sep 17 00:00:00 2001 From: abikouo Date: Mon, 29 Mar 2021 11:52:14 +0200 Subject: [PATCH 02/21] change log --- .../311-s3_bucket-allow-object-ownership-configuration.yaml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml diff --git a/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml b/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml new file mode 100644 index 00000000000..4c10dc81653 --- /dev/null +++ b/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml @@ -0,0 +1,2 @@ +minor_changes: + - s3_bucket - add new option to configure object ownership (https://github.com/ansible-collections/amazon.aws/pull/311) From 4e1e591fb95d75986b10ab0226043edde57ff8f3 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:06 +0200 Subject: [PATCH 03/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 548699895ba..88d4499acd2 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -125,7 +125,7 @@ object_ownership: description: - Allow bucket's ownership controls. - - BucketOwnerPreferred : Objects uploaded to the bucket change ownership to the bucket owner + - C(BucketOwnerPreferred) - Objects uploaded to the bucket change ownership to the bucket owner if the objects are uploaded with the bucket-owner-full-control canned ACL. - ObjectWriter: The uploading account will own the object if the object is uploaded with the bucket-owner-full-control canned ACL. From d646ec3bb6de940ac8a53d204f62025c5b582de8 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:16 +0200 Subject: [PATCH 04/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 88d4499acd2..2d381150bbc 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -127,7 +127,7 @@ - Allow bucket's ownership controls. - C(BucketOwnerPreferred) - Objects uploaded to the bucket change ownership to the bucket owner if the objects are uploaded with the bucket-owner-full-control canned ACL. - - ObjectWriter: The uploading account will own the object + - C(ObjectWriter) - The uploading account will own the object if the object is uploaded with the bucket-owner-full-control canned ACL. - This option cannot be used together with a I(delete_object_ownership) definition. choices: [ 'BucketOwnerPreferred', 'ObjectWriter' ] From b701235dc1d3c2e1d47e6d8e5362ecab449cb378 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:23 +0200 Subject: [PATCH 05/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 2d381150bbc..6cfa7ae9a48 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -138,7 +138,7 @@ - This option cannot be used together with a I(object_ownership) definition. default: false type: bool - version_added: 1.3.0 + version_added: 1.5.0 extends_documentation_fragment: - amazon.aws.aws From 72fe77dd89e8c6c46cfdfa1e0ade318258b93117 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:40 +0200 Subject: [PATCH 06/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 6cfa7ae9a48..1b4cc8a006c 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -132,6 +132,7 @@ - This option cannot be used together with a I(delete_object_ownership) definition. choices: [ 'BucketOwnerPreferred', 'ObjectWriter' ] type: str + version_added: 1.5.0 delete_object_ownership: description: - Delete bucket's ownership controls. From f19b4a80887ebfd68aac166bb148da9a0fd8537f Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:48 +0200 Subject: [PATCH 07/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 1b4cc8a006c..5525b951939 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -273,7 +273,7 @@ def create_or_update_bucket(s3_client, module, location): public_access = module.params.get("public_access") delete_public_access = module.params.get("delete_public_access") delete_object_ownership = module.params.get("delete_object_ownership") - object_ownership=module.params.get("object_ownership") + object_ownership = module.params.get("object_ownership") changed = False result = {} From b0370ec1d6fecd2721210e243ab30caba2f6f0b3 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:40:56 +0200 Subject: [PATCH 08/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 5525b951939..7b1ac9922bb 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -480,7 +480,7 @@ def create_or_update_bucket(s3_client, module, location): if delete_object_ownership or object_ownership is not None : if delete_object_ownership : # delete S3 buckect ownership - if bucket_ownership != {} : + if bucket_ownership != {}: delete_bucket_ownership(s3_client,name) changed=True result['object_ownership']=None From 61e206de17be71cb11a2fb37be2e64dbc3a9461a Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:41:31 +0200 Subject: [PATCH 09/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 7b1ac9922bb..3350f548303 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -641,23 +641,22 @@ def delete_bucket_public_access(s3_client, bucket_name): s3_client.delete_public_access_block(Bucket=bucket_name) @AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) -def delete_bucket_ownership(s3_client,bucket_name) : +def delete_bucket_ownership(s3_client, bucket_name): ''' Delete bucket ownership controls from S3 bucket ''' s3_client.delete_bucket_ownership_controls(Bucket=bucket_name) @AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) -def put_bucket_ownership(s3_client,bucket_name,target) : +def put_bucket_ownership(s3_client, bucket_name, target) : ''' Put bucket ownership controls for S3 bucket ''' s3_client.put_bucket_ownership_controls(Bucket=bucket_name, OwnershipControls={ - 'Rules': [ { 'ObjectOwnership': target } ] + 'Rules': [{'ObjectOwnership': target}] }) - def wait_policy_is_applied(module, s3_client, bucket_name, expected_policy, should_fail=True): for dummy in range(0, 12): try: From 7dec11cba18bb37435d280b0f29a8595467125cc Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:41:40 +0200 Subject: [PATCH 10/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 3350f548303..e48b16b84ca 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -888,8 +888,8 @@ def main(): block_public_policy=dict(type='bool', default=False), restrict_public_buckets=dict(type='bool', default=False))), delete_public_access=dict(type='bool', default=False), - object_ownership=dict(type='str',choices=['BucketOwnerPreferred','ObjectWriter']), - delete_object_ownership=dict(type='bool',default=False) + object_ownership=dict(type='str', choices=['BucketOwnerPreferred', 'ObjectWriter']), + delete_object_ownership=dict(type='bool', default=False), ) required_by = dict( From c33bbdadc0d3579d5b7d8afdae1d384bd659fa4f Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Mon, 29 Mar 2021 14:41:57 +0200 Subject: [PATCH 11/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index e48b16b84ca..5c0cf056e92 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -760,14 +760,14 @@ def get_bucket_public_access(s3_client, bucket_name): except is_boto3_error_code('NoSuchPublicAccessBlockConfiguration'): return {} -def get_bucket_ownership_cntrl(s3_client,bucket_name) : +def get_bucket_ownership_cntrl(s3_client, bucket_name): ''' Get current bucket public access block ''' try: bucket_ownership = s3_client.get_bucket_ownership_controls(Bucket=bucket_name) return bucket_ownership['OwnershipControls']['Rules'][0]['ObjectOwnership'] - except is_boto3_error_code([ 'OwnershipControlsNotFoundError','NoSuchOwnershipControls' ]): + except is_boto3_error_code(['OwnershipControlsNotFoundError', 'NoSuchOwnershipControls']): return None def paginated_list(s3_client, **pagination_params): From 2726341a7334b6aab7c6771a4243ddf202880f0b Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Mon, 29 Mar 2021 20:17:01 +0200 Subject: [PATCH 12/21] whitespace sanity fix --- plugins/modules/s3_bucket.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 5c0cf056e92..71bc0e5cacf 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -126,9 +126,9 @@ description: - Allow bucket's ownership controls. - C(BucketOwnerPreferred) - Objects uploaded to the bucket change ownership to the bucket owner - if the objects are uploaded with the bucket-owner-full-control canned ACL. + if the objects are uploaded with the bucket-owner-full-control canned ACL. - C(ObjectWriter) - The uploading account will own the object - if the object is uploaded with the bucket-owner-full-control canned ACL. + if the object is uploaded with the bucket-owner-full-control canned ACL. - This option cannot be used together with a I(delete_object_ownership) definition. choices: [ 'BucketOwnerPreferred', 'ObjectWriter' ] type: str @@ -475,24 +475,22 @@ def create_or_update_bucket(s3_client, module, location): result['public_access_block'] = {} # -- Bucket ownership - bucket_ownership = get_bucket_ownership_cntrl(s3_client,name) + bucket_ownership = get_bucket_ownership_cntrl(s3_client, name) result['object_ownership'] = bucket_ownership - if delete_object_ownership or object_ownership is not None : - if delete_object_ownership : + if delete_object_ownership or object_ownership is not None: + if delete_object_ownership: # delete S3 buckect ownership if bucket_ownership != {}: - delete_bucket_ownership(s3_client,name) - changed=True - result['object_ownership']=None + delete_bucket_ownership(s3_client, name) + changed = True + result['object_ownership'] = None else: # update S3 bucket ownership - if bucket_ownership != object_ownership : - put_bucket_ownership(s3_client,name,object_ownership) - changed=True + if bucket_ownership != object_ownership: + put_bucket_ownership(s3_client, name, object_ownership) + changed = True result['object_ownership'] = object_ownership - - # Module exit module.exit_json(changed=changed, name=name, **result) @@ -647,12 +645,14 @@ def delete_bucket_ownership(s3_client, bucket_name): ''' s3_client.delete_bucket_ownership_controls(Bucket=bucket_name) + @AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) -def put_bucket_ownership(s3_client, bucket_name, target) : +def put_bucket_ownership(s3_client, bucket_name, target): ''' Put bucket ownership controls for S3 bucket ''' - s3_client.put_bucket_ownership_controls(Bucket=bucket_name, + s3_client.put_bucket_ownership_controls( + Bucket=bucket_name, OwnershipControls={ 'Rules': [{'ObjectOwnership': target}] }) @@ -760,6 +760,7 @@ def get_bucket_public_access(s3_client, bucket_name): except is_boto3_error_code('NoSuchPublicAccessBlockConfiguration'): return {} + def get_bucket_ownership_cntrl(s3_client, bucket_name): ''' Get current bucket public access block @@ -770,6 +771,7 @@ def get_bucket_ownership_cntrl(s3_client, bucket_name): except is_boto3_error_code(['OwnershipControlsNotFoundError', 'NoSuchOwnershipControls']): return None + def paginated_list(s3_client, **pagination_params): pg = s3_client.get_paginator('list_objects_v2') for page in pg.paginate(**pagination_params): From 5b72b8d3b993f18957d4a8c9f70a762064221a27 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Mon, 29 Mar 2021 20:25:30 +0200 Subject: [PATCH 13/21] yet more linting. --- plugins/modules/s3_bucket.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 71bc0e5cacf..03fecbfd54a 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -638,6 +638,7 @@ def delete_bucket_public_access(s3_client, bucket_name): ''' s3_client.delete_public_access_block(Bucket=bucket_name) + @AWSRetry.exponential_backoff(max_delay=120, catch_extra_error_codes=['NoSuchBucket', 'OperationAborted']) def delete_bucket_ownership(s3_client, bucket_name): ''' @@ -657,6 +658,7 @@ def put_bucket_ownership(s3_client, bucket_name, target): 'Rules': [{'ObjectOwnership': target}] }) + def wait_policy_is_applied(module, s3_client, bucket_name, expected_policy, should_fail=True): for dummy in range(0, 12): try: From fe0742d1c223f4533bd316c0236ad0bd45a5bb12 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Fri, 2 Apr 2021 15:42:20 +0200 Subject: [PATCH 14/21] Update 311-s3_bucket-allow-object-ownership-configuration.yaml --- .../311-s3_bucket-allow-object-ownership-configuration.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml b/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml index 4c10dc81653..d822857b1d9 100644 --- a/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml +++ b/changelogs/fragments/311-s3_bucket-allow-object-ownership-configuration.yaml @@ -1,2 +1,2 @@ minor_changes: - - s3_bucket - add new option to configure object ownership (https://github.com/ansible-collections/amazon.aws/pull/311) + - s3_bucket - add new option ``object_ownership`` to configure object ownership (https://github.com/ansible-collections/amazon.aws/pull/311) From 86228e384414a63f3968bf9a4a2ed84e1e8308e9 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Thu, 8 Apr 2021 15:50:30 +0200 Subject: [PATCH 15/21] Update plugins/modules/s3_bucket.py Co-authored-by: Mark Chappell --- plugins/modules/s3_bucket.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 03fecbfd54a..aa381c61767 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -767,6 +767,8 @@ def get_bucket_ownership_cntrl(s3_client, bucket_name): ''' Get current bucket public access block ''' + if not module.botocore_at_least('1.8.11'): + return None try: bucket_ownership = s3_client.get_bucket_ownership_controls(Bucket=bucket_name) return bucket_ownership['OwnershipControls']['Rules'][0]['ObjectOwnership'] From bebde10041c69bc15e5004042c20147cb7b13e65 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Wed, 14 Apr 2021 11:13:56 +0200 Subject: [PATCH 16/21] Update s3_bucket.py --- plugins/modules/s3_bucket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index aa381c61767..6d14e16d831 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -475,7 +475,7 @@ def create_or_update_bucket(s3_client, module, location): result['public_access_block'] = {} # -- Bucket ownership - bucket_ownership = get_bucket_ownership_cntrl(s3_client, name) + bucket_ownership = get_bucket_ownership_cntrl(s3_client, module, name) result['object_ownership'] = bucket_ownership if delete_object_ownership or object_ownership is not None: if delete_object_ownership: @@ -763,7 +763,7 @@ def get_bucket_public_access(s3_client, bucket_name): return {} -def get_bucket_ownership_cntrl(s3_client, bucket_name): +def get_bucket_ownership_cntrl(s3_client, module, bucket_name): ''' Get current bucket public access block ''' From 6f131890a25a1399b229b959eb33f33d89671f0f Mon Sep 17 00:00:00 2001 From: aubin Date: Tue, 20 Apr 2021 11:00:41 +0200 Subject: [PATCH 17/21] delete ownership controls - always --- .../s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml index 5bc06e1e70d..2de5687f256 100644 --- a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml +++ b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml @@ -91,6 +91,13 @@ # ============================================================ always: + - name: delete s3 bucket ownership controls + s3_bucket: + name: '{{ bucket_name }}' + state: present + delete_object_ownership: true + ignore_errors: yes + - name: Ensure all buckets are deleted s3_bucket: name: '{{ bucket_name }}' From b28c0d3234db3b23438d955a192af0b96af96a17 Mon Sep 17 00:00:00 2001 From: aubin Date: Mon, 3 May 2021 09:34:37 +0200 Subject: [PATCH 18/21] update after code review --- plugins/modules/s3_bucket.py | 6 ++++++ .../s3_bucket/tasks/ownership_controls.yml | 20 ++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 2666236c987..1ec2fedfdfd 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -944,6 +944,12 @@ def main(): state = module.params.get("state") encryption = module.params.get("encryption") encryption_key_id = module.params.get("encryption_key_id") + delete_object_ownership = module.params.get('delete_object_ownership') + object_ownership = module.params.get('object_ownership') + + if delete_object_ownership is not None or object_ownership is not None: + if not module.botocore_at_least('1.8.11'): + module.fail_json(msg="Managing bucket ownership controls requires botocore version >= 1.8.11") if not hasattr(s3_client, "get_bucket_encryption"): if encryption is not None: diff --git a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml index 2de5687f256..72722e16ef2 100644 --- a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml +++ b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml @@ -8,10 +8,12 @@ block: # ============================================================ + - set_fact: + local_bucket_name: "{{ bucket_name | hash('md5')}}ownership" - name: 'Create a simple bucket bad value for ownership controls' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present object_ownership: default ignore_errors: true @@ -23,7 +25,7 @@ - name: 'Create bucket with object_ownership set to object_writer' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present ignore_errors: true register: output @@ -35,12 +37,12 @@ - name: delete s3 bucket s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: absent - name: 'create s3 bucket with object ownership controls' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present object_ownership: ObjectWriter register: output @@ -53,7 +55,7 @@ - name: 'update s3 bucket ownership controls' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present object_ownership: BucketOwnerPreferred register: output @@ -66,7 +68,7 @@ - name: 'test idempotency update s3 bucket ownership controls' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present object_ownership: BucketOwnerPreferred register: output @@ -79,7 +81,7 @@ - name: 'delete s3 bucket ownership controls' s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present delete_object_ownership: true register: output @@ -93,13 +95,13 @@ always: - name: delete s3 bucket ownership controls s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: present delete_object_ownership: true ignore_errors: yes - name: Ensure all buckets are deleted s3_bucket: - name: '{{ bucket_name }}' + name: '{{ local_bucket_name }}' state: absent ignore_errors: yes From d27ba071ddf21802108b6ea173467023b4d5f32e Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Tue, 4 May 2021 08:00:18 +0200 Subject: [PATCH 19/21] Update s3_bucket.py --- plugins/modules/s3_bucket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 1ec2fedfdfd..7be7aa0efae 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -132,14 +132,14 @@ - This option cannot be used together with a I(delete_object_ownership) definition. choices: [ 'BucketOwnerPreferred', 'ObjectWriter' ] type: str - version_added: 1.5.0 + version_added: 2.0.0 delete_object_ownership: description: - Delete bucket's ownership controls. - This option cannot be used together with a I(object_ownership) definition. default: false type: bool - version_added: 1.5.0 + version_added: 2.0.0 extends_documentation_fragment: - amazon.aws.aws From 0763fac49d28c92b6fb68d79a30bb54e9e1930e7 Mon Sep 17 00:00:00 2001 From: abikouo <79859644+abikouo@users.noreply.github.com> Date: Tue, 4 May 2021 10:01:34 +0200 Subject: [PATCH 20/21] Update ownership_controls.yml --- .../roles/s3_bucket/tasks/ownership_controls.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml index 72722e16ef2..c651aac861e 100644 --- a/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml +++ b/tests/integration/targets/s3_bucket/roles/s3_bucket/tasks/ownership_controls.yml @@ -90,6 +90,18 @@ that: - output.changed - not output.object_ownership|bool + + - name: 'delete s3 bucket ownership controls once again (idempotency)' + s3_bucket: + name: '{{ local_bucket_name }}' + state: present + delete_object_ownership: true + register: idempotency + + - assert: + that: + - not idempotency.changed + - not idempotency.object_ownership|bool # ============================================================ always: From aef4074a921510383bd10202709c8903a237d345 Mon Sep 17 00:00:00 2001 From: abikouo Date: Tue, 4 May 2021 14:59:20 +0200 Subject: [PATCH 21/21] bucket_ownership undefined set to None --- plugins/modules/s3_bucket.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/s3_bucket.py b/plugins/modules/s3_bucket.py index 7be7aa0efae..0ab2de88f78 100644 --- a/plugins/modules/s3_bucket.py +++ b/plugins/modules/s3_bucket.py @@ -480,7 +480,7 @@ def create_or_update_bucket(s3_client, module, location): if delete_object_ownership or object_ownership is not None: if delete_object_ownership: # delete S3 buckect ownership - if bucket_ownership != {}: + if bucket_ownership is not None: delete_bucket_ownership(s3_client, name) changed = True result['object_ownership'] = None