Esempio n. 1
0
def update_policy(connection, module, key, policy):
    if policy is None:
        return False
    try:
        new_policy = json.loads(policy)
    except ValueError as e:
        module.fail_json_aws(e, msg="Unable to parse new policy as JSON")

    key_id = key['key_arn']
    try:
        keyret = connection.get_key_policy(KeyId=key_id, PolicyName='default')
        original_policy = json.loads(keyret['Policy'])
    except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError):
        # If we can't fetch the current policy assume we're making a change
        # Could occur if we have PutKeyPolicy without GetKeyPolicy
        original_policy = {}

    if not compare_policies(original_policy, new_policy):
        return False

    if not module.check_mode:
        try:
            connection.put_key_policy(KeyId=key_id, PolicyName='default', Policy=policy)
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Unable to update key policy")

    return True
Esempio n. 2
0
def create_or_update_bucket_cors(connection, module):

    name = module.params.get("name")
    rules = module.params.get("rules", [])
    changed = False

    try:
        current_camel_rules = connection.get_bucket_cors(Bucket=name)['CORSRules']
    except ClientError:
        current_camel_rules = []

    new_camel_rules = snake_dict_to_camel_dict(rules, capitalize_first=True)
    # compare_policies() takes two dicts and makes them hashable for comparison
    if compare_policies(new_camel_rules, current_camel_rules):
        changed = True

    if changed:
        try:
            cors = connection.put_bucket_cors(Bucket=name, CORSConfiguration={'CORSRules': new_camel_rules})
        except ClientError as e:
            module.fail_json(
                msg="Unable to update CORS for bucket {0}: {1}".format(name, to_native(e)),
                exception=traceback.format_exc(),
                **camel_dict_to_snake_dict(e.response)
            )
        except BotoCoreError as e:
            module.fail_json(
                msg=to_native(e),
                exception=traceback.format_exc()
            )

    module.exit_json(changed=changed, name=name, rules=rules)
Esempio n. 3
0
def create_or_update_bucket_cors(connection, module):

    name = module.params.get("name")
    rules = module.params.get("rules", [])
    changed = False

    try:
        current_camel_rules = connection.get_bucket_cors(
            Bucket=name)['CORSRules']
    except ClientError:
        current_camel_rules = []

    new_camel_rules = snake_dict_to_camel_dict(rules, capitalize_first=True)
    # compare_policies() takes two dicts and makes them hashable for comparison
    if compare_policies(new_camel_rules, current_camel_rules):
        changed = True

    if changed:
        try:
            cors = connection.put_bucket_cors(
                Bucket=name, CORSConfiguration={'CORSRules': new_camel_rules})
        except ClientError as e:
            module.fail_json(
                msg="Unable to update CORS for bucket {0}: {1}".format(
                    name, to_native(e)),
                exception=traceback.format_exc(),
                **camel_dict_to_snake_dict(e.response))
        except BotoCoreError as e:
            module.fail_json(msg=to_native(e),
                             exception=traceback.format_exc())

    module.exit_json(changed=changed, name=name, rules=rules)
Esempio n. 4
0
 def test_compare_large_policies_without_differences(self):
     """ Testing two larger policies which are identical except for:
             * The statements are in different orders
             * The contents of the statements are also in different orders
             * The second contains a list of length one for the Principal whereas in the first it is a string
     """
     self.assertFalse(
         compare_policies(self.larger_policy_one, self.larger_policy_two))
Esempio n. 5
0
def main():
    argument_spec = dict(name=dict(required=True, type='str'),
                         role_arn=dict(required=True, type='str'),
                         artifact_store=dict(required=True, type='dict'),
                         stages=dict(required=True, type='list'),
                         version=dict(type='int'),
                         state=dict(choices=['present', 'absent'],
                                    default='present'))

    module = AnsibleAWSModule(argument_spec=argument_spec)
    client_conn = module.client('codepipeline')

    state = module.params.get('state')
    changed = False

    # Determine if the CodePipeline exists
    found_code_pipeline = describe_pipeline(client=client_conn,
                                            name=module.params['name'],
                                            version=module.params['version'],
                                            module=module)
    pipeline_result = {}

    if state == 'present':
        if 'pipeline' in found_code_pipeline:
            pipeline_dict = copy.deepcopy(found_code_pipeline['pipeline'])
            # Update dictionary with provided module params:
            pipeline_dict['roleArn'] = module.params['role_arn']
            pipeline_dict['artifactStore'] = module.params['artifact_store']
            pipeline_dict['stages'] = module.params['stages']
            if module.params['version'] is not None:
                pipeline_dict['version'] = module.params['version']

            pipeline_result = update_pipeline(client=client_conn,
                                              pipeline_dict=pipeline_dict,
                                              module=module)

            if compare_policies(found_code_pipeline['pipeline'],
                                pipeline_result['pipeline']):
                changed = True
        else:
            pipeline_result = create_pipeline(
                client=client_conn,
                name=module.params['name'],
                role_arn=module.params['role_arn'],
                artifact_store=module.params['artifact_store'],
                stages=module.params['stages'],
                version=module.params['version'],
                module=module)
            changed = True
    elif state == 'absent':
        if found_code_pipeline:
            pipeline_result = delete_pipeline(client=client_conn,
                                              name=module.params['name'],
                                              module=module)
            changed = True

    module.exit_json(changed=changed,
                     **camel_dict_to_snake_dict(pipeline_result))
Esempio n. 6
0
    def create(self):
        matching_policies = []
        policy_doc = self.get_policy_text()
        policy_match = False
        for pol in self.list():
            if not compare_policies(self.get(pol), policy_doc):
                matching_policies.append(pol)
                policy_match = True

        if (self.policy_name not in matching_policies) and not (self.skip_duplicates and policy_match):
            self.put(policy_doc)
Esempio n. 7
0
 def find_missing(self, update, current_condition):
     missing = []
     for desired in update['Updates']:
         found = False
         desired_condition = desired[self.conditiontuple]
         current_conditions = current_condition[self.conditiontuples]
         for condition in current_conditions:
             if not compare_policies(condition, desired_condition):
                 found = True
         if not found:
             missing.append(desired)
     return missing
Esempio n. 8
0
 def find_missing(self, update, current_condition):
     missing = []
     for desired in update['Updates']:
         found = False
         desired_condition = desired[self.conditiontuple]
         current_conditions = current_condition[self.conditiontuples]
         for condition in current_conditions:
             if not compare_policies(condition, desired_condition):
                 found = True
         if not found:
             missing.append(desired)
     return missing
def get_or_create_policy_version(module, iam, policy, policy_document):
    try:
        versions = iam.list_policy_versions(
            PolicyArn=policy['Arn'])['Versions']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't list policy versions: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    for v in versions:
        try:
            document = iam.get_policy_version(
                PolicyArn=policy['Arn'],
                VersionId=v['VersionId'])['PolicyVersion']['Document']
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't get policy version %s: %s" %
                             (v['VersionId'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        # If the current policy matches the existing one
        if not compare_policies(document, json.loads(
                to_native(policy_document))):
            return v, False

    # No existing version so create one
    # There is a service limit (typically 5) of policy versions.
    #
    # Rather than assume that it is 5, we'll try to create the policy
    # and if that doesn't work, delete the oldest non default policy version
    # and try again.
    if not module.check_mode:
        try:
            version = iam.create_policy_version(
                PolicyArn=policy['Arn'],
                PolicyDocument=policy_document)['PolicyVersion']
            return version, True
        except botocore.exceptions.ClientError as e:
            if e.response['Error']['Code'] == 'LimitExceeded':
                delete_oldest_non_default_version(module, iam, policy)
                try:
                    version = iam.create_policy_version(
                        PolicyArn=policy['Arn'],
                        PolicyDocument=policy_document)['PolicyVersion']
                    return version, True
                except botocore.exceptions.ClientError as e:
                    pass
            # Handle both when the exception isn't LimitExceeded or
            # the second attempt still failed
            module.fail_json(msg="Couldn't create policy version: %s" % str(e),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
    else:
        module.exit_json(changed=True)
Esempio n. 10
0
    def _set_topic_attrs(self):
        changed = False
        try:
            topic_attributes = self.connection.get_topic_attributes(TopicArn=self.topic_arn)['Attributes']
        except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
            self.module.fail_json_aws(e, msg="Couldn't get topic attributes for topic %s" % self.topic_arn)

        if self.display_name and self.display_name != topic_attributes['DisplayName']:
            changed = True
            self.attributes_set.append('display_name')
            if not self.check_mode:
                try:
                    self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='DisplayName',
                                                         AttributeValue=self.display_name)
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    self.module.fail_json_aws(e, msg="Couldn't set display name")

        if self.policy and compare_policies(self.policy, json.loads(topic_attributes['Policy'])):
            changed = True
            self.attributes_set.append('policy')
            if not self.check_mode:
                try:
                    self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='Policy',
                                                         AttributeValue=json.dumps(self.policy))
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    self.module.fail_json_aws(e, msg="Couldn't set topic policy")

        if self.delivery_policy and ('DeliveryPolicy' not in topic_attributes or
                                     compare_policies(self.delivery_policy, json.loads(topic_attributes['DeliveryPolicy']))):
            changed = True
            self.attributes_set.append('delivery_policy')
            if not self.check_mode:
                try:
                    self.connection.set_topic_attributes(TopicArn=self.topic_arn, AttributeName='DeliveryPolicy',
                                                         AttributeValue=json.dumps(self.delivery_policy))
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    self.module.fail_json_aws(e, msg="Couldn't set topic delivery policy")
        return changed
Esempio n. 11
0
def wait_policy_is_applied(module, s3_client, bucket_name, expected_policy, should_fail=True):
    for dummy in range(0, 12):
        try:
            current_policy = get_bucket_policy(s3_client, bucket_name)
        except (ClientError, BotoCoreError) as e:
            module.fail_json_aws(e, msg="Failed to get bucket policy")

        if compare_policies(current_policy, expected_policy):
            time.sleep(5)
        else:
            return current_policy
    if should_fail:
        module.fail_json(msg="Bucket policy failed to apply in the expected time")
    else:
        return None
Esempio n. 12
0
def wait_policy_is_applied(module, s3_client, bucket_name, expected_policy, should_fail=True):
    for dummy in range(0, 12):
        try:
            current_policy = get_bucket_policy(s3_client, bucket_name)
        except (ClientError, BotoCoreError) as e:
            module.fail_json_aws(e, msg="Failed to get bucket policy")

        if compare_policies(current_policy, expected_policy):
            time.sleep(5)
        else:
            return current_policy
    if should_fail:
        module.fail_json(msg="Bucket policy failed to apply in the expected time")
    else:
        return None
Esempio n. 13
0
def create_or_update_identity_policy(connection, module):
    identity = module.params.get('identity')
    policy_name = module.params.get('policy_name')
    required_policy = module.params.get('policy')
    required_policy_dict = json.loads(required_policy)

    changed = False
    policy = get_identity_policy(connection, module, identity, policy_name)
    policy_dict = json.loads(policy) if policy else None
    if compare_policies(policy_dict, required_policy_dict):
        changed = True
        try:
            if not module.check_mode:
                connection.put_identity_policy(Identity=identity,
                                               PolicyName=policy_name,
                                               Policy=required_policy,
                                               aws_retry=True)
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(
                e,
                msg='Failed to put identity policy {policy}'.format(
                    policy=policy_name))

    # Load the list of applied policies to include in the response.
    # In principle we should be able to just return the response, but given
    # eventual consistency behaviours in AWS it's plausible that we could
    # end up with a list that doesn't contain the policy we just added.
    # So out of paranoia check for this case and if we're missing the policy
    # just make sure it's present.
    #
    # As a nice side benefit this also means the return is correct in check mode
    try:
        policies_present = connection.list_identity_policies(
            Identity=identity, aws_retry=True)['PolicyNames']
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg='Failed to list identity policies')
    if policy_name is not None and policy_name not in policies_present:
        policies_present = list(policies_present)
        policies_present.append(policy_name)
    module.exit_json(
        changed=changed,
        policies=policies_present,
    )
Esempio n. 14
0
def get_or_create_policy_version(module, iam, policy, policy_document):
    try:
        versions = iam.list_policy_versions(PolicyArn=policy['Arn'])['Versions']
    except botocore.exceptions.ClientError as e:
        module.fail_json(msg="Couldn't list policy versions: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
    for v in versions:
        try:
            document = iam.get_policy_version(PolicyArn=policy['Arn'],
                                              VersionId=v['VersionId'])['PolicyVersion']['Document']
        except botocore.exceptions.ClientError as e:
            module.fail_json(msg="Couldn't get policy version %s: %s" % (v['VersionId'], str(e)),
                             exception=traceback.format_exc(),
                             **camel_dict_to_snake_dict(e.response))
        # If the current policy matches the existing one
        if not compare_policies(document, json.loads(to_native(policy_document))):
            return v, False

    # No existing version so create one
    # There is a service limit (typically 5) of policy versions.
    #
    # Rather than assume that it is 5, we'll try to create the policy
    # and if that doesn't work, delete the oldest non default policy version
    # and try again.
    try:
        version = iam.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion']
        return version, True
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'LimitExceeded':
            delete_oldest_non_default_version(module, iam, policy)
            try:
                version = iam.create_policy_version(PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion']
                return version, True
            except botocore.exceptions.ClientError as e:
                pass
        # Handle both when the exception isn't LimitExceeded or
        # the second attempt still failed
        module.fail_json(msg="Couldn't create policy version: %s" % str(e),
                         exception=traceback.format_exc(),
                         **camel_dict_to_snake_dict(e.response))
def create_or_update_identity_policy(connection, module):
    identity = module.params.get('identity')
    policy_name = module.params.get('policy_name')
    required_policy = module.params.get('policy')
    required_policy_dict = json.loads(required_policy)

    changed = False
    policy = get_identity_policy(connection, module, identity, policy_name)
    policy_dict = json.loads(policy) if policy else None
    if compare_policies(policy_dict, required_policy_dict):
        changed = True
        try:
            if not module.check_mode:
                connection.put_identity_policy(Identity=identity, PolicyName=policy_name, Policy=required_policy, aws_retry=True)
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(e, msg='Failed to put identity policy {policy}'.format(policy=policy_name))

    # Load the list of applied policies to include in the response.
    # In principle we should be able to just return the response, but given
    # eventual consistency behaviours in AWS it's plausible that we could
    # end up with a list that doesn't contain the policy we just added.
    # So out of paranoia check for this case and if we're missing the policy
    # just make sure it's present.
    #
    # As a nice side benefit this also means the return is correct in check mode
    try:
        policies_present = connection.list_identity_policies(Identity=identity, aws_retry=True)['PolicyNames']
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg='Failed to list identity policies')
    if policy_name is not None and policy_name not in policies_present:
        policies_present = list(policies_present)
        policies_present.append(policy_name)
    module.exit_json(
        changed=changed,
        policies=policies_present,
    )
Esempio n. 16
0
def run(ecr, params, verbosity):
    # type: (EcsEcr, dict, int) -> Tuple[bool, dict]
    result = {}
    try:
        name = params['name']
        state = params['state']
        policy_text = params['policy']
        delete_policy = params['delete_policy']
        registry_id = params['registry_id']
        force_set_policy = params['force_set_policy']

        # If a policy was given, parse it
        policy = policy_text and json.loads(policy_text)

        result['state'] = state
        result['created'] = False

        repo = ecr.get_repository(registry_id, name)

        if state == 'present':
            result['created'] = False
            if not repo:
                repo = ecr.create_repository(registry_id, name)
                result['changed'] = True
                result['created'] = True
            result['repository'] = repo

            if delete_policy:
                original_policy = ecr.get_repository_policy(registry_id, name)

                if verbosity >= 2:
                    result['policy'] = None

                if verbosity >= 3:
                    result['original_policy'] = original_policy

                if original_policy:
                    ecr.delete_repository_policy(registry_id, name)
                    result['changed'] = True

            elif policy_text is not None:
                try:
                    # Sort any lists containing only string types
                    policy = sort_lists_of_strings(policy)

                    if verbosity >= 2:
                        result['policy'] = policy
                    original_policy = ecr.get_repository_policy(
                        registry_id, name)

                    if original_policy:
                        original_policy = sort_lists_of_strings(
                            original_policy)

                    if verbosity >= 3:
                        result['original_policy'] = original_policy

                    if compare_policies(original_policy, policy):
                        ecr.set_repository_policy(registry_id, name,
                                                  policy_text,
                                                  force_set_policy)
                        result['changed'] = True
                except Exception:
                    # Some failure w/ the policy. It's helpful to know what the
                    # policy is.
                    result['policy'] = policy_text
                    raise

        elif state == 'absent':
            result['name'] = name
            if repo:
                ecr.delete_repository(registry_id, name)
                result['changed'] = True

    except Exception as err:
        msg = str(err)
        if isinstance(err, ClientError):
            msg = boto_exception(err)
        result['msg'] = msg
        result['exception'] = traceback.format_exc()
        return False, result

    if ecr.skipped:
        result['skipped'] = True

    if ecr.changed:
        result['changed'] = True

    return True, result
Esempio n. 17
0
def create_or_update_bucket(s3_client, module, location):

    policy = module.params.get("policy")
    name = module.params.get("name")
    requester_pays = module.params.get("requester_pays")
    tags = module.params.get("tags")
    versioning = module.params.get("versioning")
    changed = False

    try:
        bucket_is_present = bucket_exists(s3_client, name)
    except EndpointConnectionError as e:
        module.fail_json_aws(e, msg="Invalid endpoint provided: %s" % to_text(e))
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg="Failed to check bucket presence")

    if not bucket_is_present:
        try:
            bucket_changed = create_bucket(s3_client, name, location)
            s3_client.get_waiter('bucket_exists').wait(Bucket=name)
            changed = changed or bucket_changed
        except WaiterError as e:
            module.fail_json_aws(e, msg='An error occurred waiting for the bucket to become available')
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(e, msg="Failed while creating bucket")

    # Versioning
    try:
        versioning_status = get_bucket_versioning(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket versioning")

    if versioning is not None:
        required_versioning = None
        if versioning and versioning_status.get('Status') != "Enabled":
            required_versioning = 'Enabled'
        elif not versioning and versioning_status.get('Status') == "Enabled":
            required_versioning = 'Suspended'

        if required_versioning:
            try:
                put_bucket_versioning(s3_client, name, required_versioning)
                changed = True
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Failed to update bucket versioning")

            versioning_status = wait_versioning_is_applied(module, s3_client, name, required_versioning)

    # This output format is there to ensure compatibility with previous versions of the module
    versioning_return_value = {
        'Versioning': versioning_status.get('Status', 'Disabled'),
        'MfaDelete': versioning_status.get('MFADelete', 'Disabled'),
    }

    # Requester pays
    try:
        requester_pays_status = get_bucket_request_payment(s3_client, name)
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket request payment")

    payer = 'Requester' if requester_pays else 'BucketOwner'
    if requester_pays_status != payer:
        put_bucket_request_payment(s3_client, name, payer)
        requester_pays_status = wait_payer_is_applied(module, s3_client, name, payer, should_fail=False)
        if requester_pays_status is None:
            # We have seen that it happens quite a lot of times that the put request was not taken into
            # account, so we retry one more time
            put_bucket_request_payment(s3_client, name, payer)
            requester_pays_status = wait_payer_is_applied(module, s3_client, name, payer, should_fail=True)
        changed = True

    # Policy
    try:
        current_policy = get_bucket_policy(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket policy")

    if policy is not None:
        if isinstance(policy, string_types):
            policy = json.loads(policy)

        if not policy and current_policy:
            try:
                delete_bucket_policy(s3_client, name)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Failed to delete bucket policy")
            current_policy = wait_policy_is_applied(module, s3_client, name, policy)
            changed = True
        elif compare_policies(current_policy, policy):
            try:
                put_bucket_policy(s3_client, name, policy)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Failed to update bucket policy")
            current_policy = wait_policy_is_applied(module, s3_client, name, policy, should_fail=False)
            if current_policy is None:
                # As for request payement, it happens quite a lot of times that the put request was not taken into
                # account, so we retry one more time
                put_bucket_policy(s3_client, name, policy)
                current_policy = wait_policy_is_applied(module, s3_client, name, policy, should_fail=True)
            changed = True

    # Tags
    try:
        current_tags_dict = get_current_bucket_tags_dict(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket tags")

    if tags is not None:
        if current_tags_dict != tags:
            if tags:
                try:
                    put_bucket_tagging(s3_client, name, tags)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e, msg="Failed to update bucket tags")
            else:
                try:
                    delete_bucket_tagging(s3_client, name)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e, msg="Failed to delete bucket tags")
            wait_tags_are_applied(module, s3_client, name, tags)
            current_tags_dict = tags
            changed = True

    module.exit_json(changed=changed, name=name, versioning=versioning_return_value,
                     requester_pays=requester_pays, policy=current_policy, tags=current_tags_dict)
Esempio n. 18
0
def create_or_update_bucket(s3_client, module, location):

    policy = module.params.get("policy")
    name = module.params.get("name")
    requester_pays = module.params.get("requester_pays")
    tags = module.params.get("tags")
    versioning = module.params.get("versioning")
    changed = False

    try:
        bucket_is_present = bucket_exists(s3_client, name)
    except EndpointConnectionError as e:
        module.fail_json_aws(e,
                             msg="Invalid endpoint provided: %s" % to_text(e))
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg="Failed to check bucket presence")

    if not bucket_is_present:
        try:
            bucket_changed = create_bucket(s3_client, name, location)
            s3_client.get_waiter('bucket_exists').wait(Bucket=name)
            changed = changed or bucket_changed
        except WaiterError as e:
            module.fail_json_aws(
                e,
                msg=
                'An error occurred waiting for the bucket to become available')
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(e, msg="Failed while creating bucket")

    # Versioning
    try:
        versioning_status = get_bucket_versioning(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket versioning")

    if versioning is not None:
        required_versioning = None
        if versioning and versioning_status.get('Status') != "Enabled":
            required_versioning = 'Enabled'
        elif not versioning and versioning_status.get('Status') == "Enabled":
            required_versioning = 'Suspended'

        if required_versioning:
            try:
                put_bucket_versioning(s3_client, name, required_versioning)
                changed = True
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e,
                                     msg="Failed to update bucket versioning")

            versioning_status = wait_versioning_is_applied(
                module, s3_client, name, required_versioning)

    # This output format is there to ensure compatibility with previous versions of the module
    versioning_return_value = {
        'Versioning': versioning_status.get('Status', 'Disabled'),
        'MfaDelete': versioning_status.get('MFADelete', 'Disabled'),
    }

    # Requester pays
    try:
        requester_pays_status = get_bucket_request_payment(s3_client, name)
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket request payment")

    payer = 'Requester' if requester_pays else 'BucketOwner'
    if requester_pays_status != payer:
        put_bucket_request_payment(s3_client, name, payer)
        requester_pays_status = wait_payer_is_applied(module,
                                                      s3_client,
                                                      name,
                                                      payer,
                                                      should_fail=False)
        if requester_pays_status is None:
            # We have seen that it happens quite a lot of times that the put request was not taken into
            # account, so we retry one more time
            put_bucket_request_payment(s3_client, name, payer)
            requester_pays_status = wait_payer_is_applied(module,
                                                          s3_client,
                                                          name,
                                                          payer,
                                                          should_fail=True)
        changed = True

    # Policy
    try:
        current_policy = get_bucket_policy(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket policy")

    if policy is not None:
        if isinstance(policy, string_types):
            policy = json.loads(policy)

        if not policy and current_policy:
            try:
                delete_bucket_policy(s3_client, name)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Failed to delete bucket policy")
            current_policy = wait_policy_is_applied(module, s3_client, name,
                                                    policy)
            changed = True
        elif compare_policies(current_policy, policy):
            try:
                put_bucket_policy(s3_client, name, policy)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Failed to update bucket policy")
            current_policy = wait_policy_is_applied(module,
                                                    s3_client,
                                                    name,
                                                    policy,
                                                    should_fail=False)
            if current_policy is None:
                # As for request payement, it happens quite a lot of times that the put request was not taken into
                # account, so we retry one more time
                put_bucket_policy(s3_client, name, policy)
                current_policy = wait_policy_is_applied(module,
                                                        s3_client,
                                                        name,
                                                        policy,
                                                        should_fail=True)
            changed = True

    # Tags
    try:
        current_tags_dict = get_current_bucket_tags_dict(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket tags")

    if tags is not None:
        if current_tags_dict != tags:
            if tags:
                try:
                    put_bucket_tagging(s3_client, name, tags)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e, msg="Failed to update bucket tags")
            else:
                try:
                    delete_bucket_tagging(s3_client, name)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e, msg="Failed to delete bucket tags")
            wait_tags_are_applied(module, s3_client, name, tags)
            current_tags_dict = tags
            changed = True

    module.exit_json(changed=changed,
                     name=name,
                     versioning=versioning_return_value,
                     requester_pays=requester_pays,
                     policy=current_policy,
                     tags=current_tags_dict)
Esempio n. 19
0
def _create_or_update_bucket(connection, module, location):

    policy = module.params.get("policy")
    name = module.params.get("name")
    requester_pays = module.params.get("requester_pays")
    tags = module.params.get("tags")
    versioning = module.params.get("versioning")
    changed = False

    try:
        bucket = connection.get_bucket(name)
    except S3ResponseError as e:
        try:
            bucket = connection.create_bucket(name, location=location)
            changed = True
        except (S3CreateError, BotoClientError) as e:
            module.fail_json(msg=e.message)

    # Versioning
    versioning_status = bucket.get_versioning_status()
    if versioning is not None:
        if versioning and versioning_status.get('Versioning') != "Enabled":
            try:
                bucket.configure_versioning(versioning)
                changed = True
                versioning_status = bucket.get_versioning_status()
            except S3ResponseError as e:
                module.fail_json(msg=e.message, exception=traceback.format_exc())
        elif not versioning and versioning_status.get('Versioning') == "Enabled":
            try:
                bucket.configure_versioning(versioning)
                changed = True
                versioning_status = bucket.get_versioning_status()
            except S3ResponseError as e:
                module.fail_json(msg=e.message, exception=traceback.format_exc())

    # Requester pays
    requester_pays_status = get_request_payment_status(bucket)
    if requester_pays_status != requester_pays:
        if requester_pays:
            payer = 'Requester'
        else:
            payer = 'BucketOwner'
        bucket.set_request_payment(payer=payer)
        changed = True
        requester_pays_status = get_request_payment_status(bucket)

    # Policy
    try:
        current_policy = json.loads(to_native(bucket.get_policy()))
    except S3ResponseError as e:
        if e.error_code == "NoSuchBucketPolicy":
            current_policy = {}
        else:
            module.fail_json(msg=e.message)
    if policy is not None:
        if isinstance(policy, string_types):
            policy = json.loads(policy)

        if not policy:
            bucket.delete_policy()
            # only show changed if there was already a policy
            changed = bool(current_policy)

        elif compare_policies(current_policy, policy):
            changed = True
            try:
                bucket.set_policy(json.dumps(policy))
                current_policy = json.loads(to_native(bucket.get_policy()))
            except S3ResponseError as e:
                module.fail_json(msg=e.message)

    # Tags
    try:
        current_tags = bucket.get_tags()
    except S3ResponseError as e:
        if e.error_code == "NoSuchTagSet":
            current_tags = None
        else:
            module.fail_json(msg=e.message)

    if current_tags is None:
        current_tags_dict = {}
    else:
        current_tags_dict = dict((t.key, t.value) for t in current_tags[0])

    if tags is not None:
        if current_tags_dict != tags:
            try:
                if tags:
                    bucket.set_tags(create_tags_container(tags))
                else:
                    bucket.delete_tags()
                current_tags_dict = tags
                changed = True
            except S3ResponseError as e:
                module.fail_json(msg=e.message)

    module.exit_json(changed=changed, name=bucket.name, versioning=versioning_status,
                     requester_pays=requester_pays_status, policy=current_policy, tags=current_tags_dict)
Esempio n. 20
0
 def test_compare_numeric_policy_number_and_string_are_equal(self):
     """ Testing two policies one using a quoted number, the other an int """
     self.assertFalse(
         compare_policies(self.numeric_policy_string,
                          self.numeric_policy_number))
Esempio n. 21
0
 def test_compare_boolean_policy_bool_and_string_are_equal(self):
     """ Testing two policies one using a quoted boolean, the other a bool """
     self.assertFalse(
         compare_policies(self.bool_policy_string, self.bool_policy_bool))
Esempio n. 22
0
 def test_compare_smaller_policy_with_larger(self):
     """ Testing two policies of different sizes """
     self.assertTrue(
         compare_policies(self.larger_policy_one, self.small_policy_one))
Esempio n. 23
0
 def test_compare_larger_policies_with_difference(self):
     """ Testing two larger policies which are identical except for:
             * one different principal
     """
     self.assertTrue(
         compare_policies(self.larger_policy_two, self.larger_policy_three))
Esempio n. 24
0
def run(ecr, params):
    # type: (EcsEcr, dict, int) -> Tuple[bool, dict]
    result = {}
    try:
        name = params['name']
        state = params['state']
        policy_text = params['policy']
        purge_policy = params['purge_policy']
        registry_id = params['registry_id']
        force_set_policy = params['force_set_policy']
        image_tag_mutability = params['image_tag_mutability'].upper()
        lifecycle_policy_text = params['lifecycle_policy']
        purge_lifecycle_policy = params['purge_lifecycle_policy']

        # Parse policies, if they are given
        try:
            policy = policy_text and json.loads(policy_text)
        except ValueError:
            result['policy'] = policy_text
            result['msg'] = 'Could not parse policy'
            return False, result

        try:
            lifecycle_policy = \
                lifecycle_policy_text and json.loads(lifecycle_policy_text)
        except ValueError:
            result['lifecycle_policy'] = lifecycle_policy_text
            result['msg'] = 'Could not parse lifecycle_policy'
            return False, result

        result['state'] = state
        result['created'] = False

        repo = ecr.get_repository(registry_id, name)

        if state == 'present':
            result['created'] = False

            if not repo:
                repo = ecr.create_repository(registry_id, name,
                                             image_tag_mutability)
                result['changed'] = True
                result['created'] = True
            else:
                repo = ecr.put_image_tag_mutability(registry_id, name,
                                                    image_tag_mutability)
            result['repository'] = repo

            if purge_lifecycle_policy:
                original_lifecycle_policy = \
                    ecr.get_lifecycle_policy(registry_id, name)

                result['lifecycle_policy'] = None

                if original_lifecycle_policy:
                    ecr.purge_lifecycle_policy(registry_id, name)
                    result['changed'] = True

            elif lifecycle_policy_text is not None:
                try:
                    lifecycle_policy = sort_json_policy_dict(lifecycle_policy)
                    result['lifecycle_policy'] = lifecycle_policy

                    original_lifecycle_policy = ecr.get_lifecycle_policy(
                        registry_id, name)

                    if original_lifecycle_policy:
                        original_lifecycle_policy = sort_json_policy_dict(
                            original_lifecycle_policy)

                    if original_lifecycle_policy != lifecycle_policy:
                        ecr.put_lifecycle_policy(registry_id, name,
                                                 lifecycle_policy_text)
                        result['changed'] = True
                except Exception:
                    # Some failure w/ the policy. It's helpful to know what the
                    # policy is.
                    result['lifecycle_policy'] = lifecycle_policy_text
                    raise

            if purge_policy:
                original_policy = ecr.get_repository_policy(registry_id, name)

                result['policy'] = None

                if original_policy:
                    ecr.delete_repository_policy(registry_id, name)
                    result['changed'] = True

            elif policy_text is not None:
                try:
                    # Sort any lists containing only string types
                    policy = sort_lists_of_strings(policy)

                    result['policy'] = policy

                    original_policy = ecr.get_repository_policy(
                        registry_id, name)
                    if original_policy:
                        original_policy = sort_lists_of_strings(
                            original_policy)

                    if compare_policies(original_policy, policy):
                        ecr.set_repository_policy(registry_id, name,
                                                  policy_text,
                                                  force_set_policy)
                        result['changed'] = True
                except Exception:
                    # Some failure w/ the policy. It's helpful to know what the
                    # policy is.
                    result['policy'] = policy_text
                    raise

        elif state == 'absent':
            result['name'] = name
            if repo:
                ecr.delete_repository(registry_id, name)
                result['changed'] = True

    except Exception as err:
        msg = str(err)
        if isinstance(err, ClientError):
            msg = boto_exception(err)
        result['msg'] = msg
        result['exception'] = traceback.format_exc()
        return False, result

    if ecr.skipped:
        result['skipped'] = True

    if ecr.changed:
        result['changed'] = True

    return True, result
Esempio n. 25
0
def update_key(connection, module, key):
    changed = False
    alias = module.params.get('alias')
    key_id = key['key_arn']

    if alias:
        changed = update_alias(connection, module, key_id, alias) or changed

    if key['key_state'] == 'PendingDeletion':
        try:
            connection.cancel_key_deletion(KeyId=key_id)
            # key is disabled after deletion cancellation
            # set this so that ensure_enabled_disabled works correctly
            key['key_state'] = 'Disabled'
            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Failed to cancel key deletion")

    changed = ensure_enabled_disabled(connection, module, key) or changed

    description = module.params.get('description')
    # don't update description if description is not set
    # (means you can't remove a description completely)
    if description and key['description'] != description:
        try:
            connection.update_key_description(KeyId=key_id,
                                              Description=description)
            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Failed to update key description")

    desired_tags = module.params.get('tags')
    to_add, to_remove = compare_aws_tags(key['tags'], desired_tags,
                                         module.params.get('purge_tags'))
    if to_remove:
        try:
            connection.untag_resource(KeyId=key_id, TagKeys=to_remove)
            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Unable to remove or update tag")
    if to_add:
        try:
            connection.tag_resource(KeyId=key_id,
                                    Tags=[{
                                        'TagKey': tag_key,
                                        'TagValue': desired_tags[tag_key]
                                    } for tag_key in to_add])
            changed = True
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            module.fail_json_aws(e, msg="Unable to add tag to key")

    # Update existing policy before trying to tweak grants
    if module.params.get('policy'):
        policy = module.params.get('policy')
        try:
            keyret = connection.get_key_policy(KeyId=key_id,
                                               PolicyName='default')
        except (botocore.exceptions.ClientError,
                botocore.exceptions.BotoCoreError) as e:
            # If we can't fetch the current policy assume we're making a change
            # Could occur if we have PutKeyPolicy without GetKeyPolicy
            original_policy = {}
        original_policy = json.loads(keyret['Policy'])
        try:
            new_policy = json.loads(policy)
        except ValueError as e:
            module.fail_json_aws(e, msg="Unable to parse new policy as JSON")
        if compare_policies(original_policy, new_policy):
            changed = True
            if not module.check_mode:
                try:
                    connection.put_key_policy(KeyId=key_id,
                                              PolicyName='default',
                                              Policy=policy)
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, msg="Unable to update key policy")

    desired_grants = module.params.get('grants')
    existing_grants = key['grants']

    to_add, to_remove = compare_grants(existing_grants, desired_grants,
                                       module.params.get('purge_grants'))
    if to_remove:
        for grant in to_remove:
            try:
                connection.retire_grant(KeyId=key_id,
                                        GrantId=grant['grant_id'])
                changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Unable to retire grant")

    if to_add:
        for grant in to_add:
            grant_params = convert_grant_params(grant, key)
            try:
                connection.create_grant(**grant_params)
                changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Unable to create grant")

    # make results consistent with kms_facts before returning
    result = get_key_details(connection, module, key_id)
    module.exit_json(changed=changed, **result)
Esempio n. 26
0
def create_or_update_bucket(s3_client, module, location):

    policy = module.params.get("policy")
    name = module.params.get("name")
    requester_pays = module.params.get("requester_pays")
    tags = module.params.get("tags")
    purge_tags = module.params.get("purge_tags")
    versioning = module.params.get("versioning")
    encryption = module.params.get("encryption")
    encryption_key_id = module.params.get("encryption_key_id")
    changed = False
    result = {}

    try:
        bucket_is_present = bucket_exists(s3_client, name)
    except EndpointConnectionError as e:
        module.fail_json_aws(e,
                             msg="Invalid endpoint provided: %s" % to_text(e))
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg="Failed to check bucket presence")

    if not bucket_is_present:
        try:
            bucket_changed = create_bucket(s3_client, name, location)
            s3_client.get_waiter('bucket_exists').wait(Bucket=name)
            changed = changed or bucket_changed
        except WaiterError as e:
            module.fail_json_aws(
                e,
                msg=
                'An error occurred waiting for the bucket to become available')
        except (BotoCoreError, ClientError) as e:
            module.fail_json_aws(e, msg="Failed while creating bucket")

    # Versioning
    try:
        versioning_status = get_bucket_versioning(s3_client, name)
    except BotoCoreError as exp:
        module.fail_json_aws(exp, msg="Failed to get bucket versioning")
    except ClientError as exp:
        if exp.response['Error'][
                'Code'] != 'NotImplemented' or versioning is not None:
            module.fail_json_aws(exp, msg="Failed to get bucket versioning")
    else:
        if versioning is not None:
            required_versioning = None
            if versioning and versioning_status.get('Status') != "Enabled":
                required_versioning = 'Enabled'
            elif not versioning and versioning_status.get(
                    'Status') == "Enabled":
                required_versioning = 'Suspended'

            if required_versioning:
                try:
                    put_bucket_versioning(s3_client, name, required_versioning)
                    changed = True
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(
                        e, msg="Failed to update bucket versioning")

                versioning_status = wait_versioning_is_applied(
                    module, s3_client, name, required_versioning)

        # This output format is there to ensure compatibility with previous versions of the module
        result['versioning'] = {
            'Versioning': versioning_status.get('Status', 'Disabled'),
            'MfaDelete': versioning_status.get('MFADelete', 'Disabled'),
        }

    # Requester pays
    try:
        requester_pays_status = get_bucket_request_payment(s3_client, name)
    except BotoCoreError as exp:
        module.fail_json_aws(exp, msg="Failed to get bucket request payment")
    except ClientError as exp:
        if exp.response['Error']['Code'] not in (
                'NotImplemented', 'XNotImplemented') or requester_pays:
            module.fail_json_aws(exp,
                                 msg="Failed to get bucket request payment")
    else:
        if requester_pays:
            payer = 'Requester' if requester_pays else 'BucketOwner'
            if requester_pays_status != payer:
                put_bucket_request_payment(s3_client, name, payer)
                requester_pays_status = wait_payer_is_applied(
                    module, s3_client, name, payer, should_fail=False)
                if requester_pays_status is None:
                    # We have seen that it happens quite a lot of times that the put request was not taken into
                    # account, so we retry one more time
                    put_bucket_request_payment(s3_client, name, payer)
                    requester_pays_status = wait_payer_is_applied(
                        module, s3_client, name, payer, should_fail=True)
                changed = True

        result['requester_pays'] = requester_pays

    # Policy
    try:
        current_policy = get_bucket_policy(s3_client, name)
    except BotoCoreError as exp:
        module.fail_json_aws(exp, msg="Failed to get bucket policy")
    except ClientError as exp:
        if exp.response['Error'][
                'Code'] != 'NotImplemented' or policy is not None:
            module.fail_json_aws(exp, msg="Failed to get bucket policy")
    else:
        if policy is not None:
            if isinstance(policy, string_types):
                policy = json.loads(policy)

            if not policy and current_policy:
                try:
                    delete_bucket_policy(s3_client, name)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e,
                                         msg="Failed to delete bucket policy")
                current_policy = wait_policy_is_applied(
                    module, s3_client, name, policy)
                changed = True
            elif compare_policies(current_policy, policy):
                try:
                    put_bucket_policy(s3_client, name, policy)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e,
                                         msg="Failed to update bucket policy")
                current_policy = wait_policy_is_applied(module,
                                                        s3_client,
                                                        name,
                                                        policy,
                                                        should_fail=False)
                if current_policy is None:
                    # As for request payement, it happens quite a lot of times that the put request was not taken into
                    # account, so we retry one more time
                    put_bucket_policy(s3_client, name, policy)
                    current_policy = wait_policy_is_applied(module,
                                                            s3_client,
                                                            name,
                                                            policy,
                                                            should_fail=True)
                changed = True

        result['policy'] = current_policy

    # Tags
    try:
        current_tags_dict = get_current_bucket_tags_dict(s3_client, name)
    except BotoCoreError as exp:
        module.fail_json_aws(exp, msg="Failed to get bucket tags")
    except ClientError as exp:
        if exp.response['Error']['Code'] not in (
                'NotImplemented', 'XNotImplemented') or tags is not None:
            module.fail_json_aws(exp, msg="Failed to get bucket tags")
    else:
        if tags is not None:
            # Tags are always returned as text
            tags = dict((to_text(k), to_text(v)) for k, v in tags.items())
            if not purge_tags:
                # Ensure existing tags that aren't updated by desired tags remain
                current_copy = current_tags_dict.copy()
                current_copy.update(tags)
                tags = current_copy
            if current_tags_dict != tags:
                if tags:
                    try:
                        put_bucket_tagging(s3_client, name, tags)
                    except (BotoCoreError, ClientError) as e:
                        module.fail_json_aws(
                            e, msg="Failed to update bucket tags")
                else:
                    if purge_tags:
                        try:
                            delete_bucket_tagging(s3_client, name)
                        except (BotoCoreError, ClientError) as e:
                            module.fail_json_aws(
                                e, msg="Failed to delete bucket tags")
                current_tags_dict = wait_tags_are_applied(
                    module, s3_client, name, tags)
                changed = True

        result['tags'] = current_tags_dict

    # Encryption
    try:
        current_encryption = get_bucket_encryption(s3_client, name)
    except (ClientError, BotoCoreError) as e:
        module.fail_json_aws(e, msg="Failed to get bucket encryption")

    if encryption is not None:
        current_encryption_algorithm = current_encryption.get(
            'SSEAlgorithm') if current_encryption else None
        current_encryption_key = current_encryption.get(
            'KMSMasterKeyID') if current_encryption else None
        if encryption == 'none' and current_encryption_algorithm is not None:
            try:
                delete_bucket_encryption(s3_client, name)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e,
                                     msg="Failed to delete bucket encryption")
            current_encryption = wait_encryption_is_applied(
                module, s3_client, name, None)
            changed = True
        elif encryption != 'none' and (
                encryption != current_encryption_algorithm) or (
                    encryption == 'aws:kms'
                    and current_encryption_key != encryption_key_id):
            expected_encryption = {'SSEAlgorithm': encryption}
            if encryption == 'aws:kms' and encryption_key_id is not None:
                expected_encryption.update(
                    {'KMSMasterKeyID': encryption_key_id})
            current_encryption = put_bucket_encryption_with_retry(
                module, s3_client, name, expected_encryption)
            changed = True

        result['encryption'] = current_encryption

    module.exit_json(changed=changed, name=name, **result)
Esempio n. 27
0
def compare_assume_role_policy_doc(current_policy_doc, new_policy_doc):
    if not compare_policies(current_policy_doc, json.loads(new_policy_doc)):
        return True
    else:
        return False