diff --git a/changelogs/fragments/migrate_iam_group.yml b/changelogs/fragments/migrate_iam_group.yml deleted file mode 100644 index 0fa4f7c0c36..00000000000 --- a/changelogs/fragments/migrate_iam_group.yml +++ /dev/null @@ -1,4 +0,0 @@ -major_changes: -- iam_group - The module has been migrated from the ``community.aws`` collection. - Playbooks using the Fully Qualified Collection Name for this module should be updated - to use ``amazon.aws.iam_group`` (https://github.com/ansible-collections/amazon.aws/pull/1755). diff --git a/meta/runtime.yml b/meta/runtime.yml index 007f42aaa72..c627df5be2b 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -9,10 +9,10 @@ action_groups: - aws_s3 - backup_plan - backup_plan_info - - backup_selection - - backup_selection_info - backup_tag - backup_tag_info + - backup_selection + - backup_selection_info - backup_vault - backup_vault_info - cloudformation @@ -20,12 +20,12 @@ action_groups: - cloudtrail - cloudtrail_info - cloudwatch_metric_alarm - - cloudwatch_metric_alarm_info - cloudwatchevent_rule - cloudwatchevent_rule - cloudwatchlogs_log_group - cloudwatchlogs_log_group_info - cloudwatchlogs_log_group_metric_filter + - cloudwatch_metric_alarm_info - ec2_ami - ec2_ami_info - ec2_eip @@ -68,7 +68,6 @@ action_groups: - elb_application_lb_info - elb_classic_lb - execute_lambda - - iam_group - iam_instance_profile - iam_instance_profile_info - iam_policy diff --git a/plugins/modules/iam_group.py b/plugins/modules/iam_group.py deleted file mode 100644 index d8411191d88..00000000000 --- a/plugins/modules/iam_group.py +++ /dev/null @@ -1,413 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: Contributors to the Ansible project -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -DOCUMENTATION = r""" ---- -module: iam_group -version_added: 1.0.0 -version_added_collection: community.aws -short_description: Manage AWS IAM groups -description: - - Manage AWS IAM groups. -author: - - Nick Aslanidis (@naslanidis) - - Maksym Postument (@infectsoldier) -options: - name: - description: - - The name of the group to create. - required: true - type: str - managed_policies: - description: - - A list of managed policy ARNs or friendly names to attach to the role. - - To embed an inline policy, use M(amazon.aws.iam_policy). - required: false - type: list - elements: str - default: [] - aliases: ['managed_policy'] - users: - description: - - A list of existing users to add as members of the group. - required: false - type: list - elements: str - default: [] - state: - description: - - Create or remove the IAM group. - required: true - choices: [ 'present', 'absent' ] - type: str - purge_policies: - description: - - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched. - required: false - default: false - type: bool - aliases: ['purge_policy', 'purge_managed_policies'] - purge_users: - description: - - When I(purge_users=true) users which are not included in I(users) will be detached. - required: false - default: false - type: bool -extends_documentation_fragment: - - amazon.aws.common.modules - - amazon.aws.region.modules - - amazon.aws.boto3 -""" - -EXAMPLES = r""" -# Note: These examples do not set authentication details, see the AWS Guide for details. - -- name: Create a group - amazon.aws.iam_group: - name: testgroup1 - state: present - -- name: Create a group and attach a managed policy using its ARN - amazon.aws.iam_group: - name: testgroup1 - managed_policies: - - arn:aws:iam::aws:policy/AmazonSNSFullAccess - state: present - -- name: Create a group with users as members and attach a managed policy using its ARN - amazon.aws.iam_group: - name: testgroup1 - managed_policies: - - arn:aws:iam::aws:policy/AmazonSNSFullAccess - users: - - test_user1 - - test_user2 - state: present - -- name: Remove all managed policies from an existing group with an empty list - amazon.aws.iam_group: - name: testgroup1 - state: present - purge_policies: true - -- name: Remove all group members from an existing group - amazon.aws.iam_group: - name: testgroup1 - managed_policies: - - arn:aws:iam::aws:policy/AmazonSNSFullAccess - purge_users: true - state: present - -- name: Delete the group - amazon.aws.iam_group: - name: testgroup1 - state: absent - -""" -RETURN = r""" -iam_group: - description: dictionary containing all the group information including group membership - returned: success - type: complex - contains: - group: - description: dictionary containing all the group information - returned: success - type: complex - contains: - arn: - description: the Amazon Resource Name (ARN) specifying the group - type: str - sample: "arn:aws:iam::1234567890:group/testgroup1" - create_date: - description: the date and time, in ISO 8601 date-time format, when the group was created - type: str - sample: "2017-02-08T04:36:28+00:00" - group_id: - description: the stable and unique string identifying the group - type: str - sample: AGPA12345EXAMPLE54321 - group_name: - description: the friendly name that identifies the group - type: str - sample: testgroup1 - path: - description: the path to the group - type: str - sample: / - users: - description: list containing all the group members - returned: success - type: complex - contains: - arn: - description: the Amazon Resource Name (ARN) specifying the user - type: str - sample: "arn:aws:iam::1234567890:user/test_user1" - create_date: - description: the date and time, in ISO 8601 date-time format, when the user was created - type: str - sample: "2017-02-08T04:36:28+00:00" - user_id: - description: the stable and unique string identifying the user - type: str - sample: AIDA12345EXAMPLE54321 - user_name: - description: the friendly name that identifies the user - type: str - sample: testgroup1 - path: - description: the path to the user - type: str - sample: / -""" - -try: - import botocore -except ImportError: - pass # caught by AnsibleAWSModule - -from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict - -from ansible_collections.amazon.aws.plugins.module_utils.arn import validate_aws_arn -from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code -from ansible_collections.amazon.aws.plugins.module_utils.modules import AnsibleAWSModule -from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry - - -def compare_attached_group_policies(current_attached_policies, new_attached_policies): - # If new_attached_policies is None it means we want to remove all policies - if len(current_attached_policies) > 0 and new_attached_policies is None: - return False - - current_attached_policies_arn_list = [] - for policy in current_attached_policies: - current_attached_policies_arn_list.append(policy["PolicyArn"]) - - if set(current_attached_policies_arn_list) == set(new_attached_policies): - return True - else: - return False - - -def compare_group_members(current_group_members, new_group_members): - # If new_attached_policies is None it means we want to remove all policies - if len(current_group_members) > 0 and new_group_members is None: - return False - if set(current_group_members) == set(new_group_members): - return True - else: - return False - - -def convert_friendly_names_to_arns(connection, module, policy_names): - if all(validate_aws_arn(policy, service="iam") for policy in policy_names if policy is not None): - return policy_names - allpolicies = {} - paginator = connection.get_paginator("list_policies") - policies = paginator.paginate().build_full_result()["Policies"] - - for policy in policies: - allpolicies[policy["PolicyName"]] = policy["Arn"] - allpolicies[policy["Arn"]] = policy["Arn"] - try: - return [allpolicies[policy] for policy in policy_names if policy is not None] - except KeyError as e: - module.fail_json(msg="Couldn't find policy: " + str(e)) - - -def create_or_update_group(connection, module): - params = dict() - params["GroupName"] = module.params.get("name") - managed_policies = module.params.get("managed_policies") - users = module.params.get("users") - purge_users = module.params.get("purge_users") - purge_policies = module.params.get("purge_policies") - changed = False - if managed_policies: - managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies) - - # Get group - try: - group = get_group(connection, module, params["GroupName"]) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg="Couldn't get group") - - # If group is None, create it - if group is None: - # Check mode means we would create the group - if module.check_mode: - module.exit_json(changed=True) - - try: - group = connection.create_group(**params) - changed = True - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg="Couldn't create group") - - # Manage managed policies - current_attached_policies = get_attached_policy_list(connection, module, params["GroupName"]) - if not compare_attached_group_policies(current_attached_policies, managed_policies): - current_attached_policies_arn_list = [] - for policy in current_attached_policies: - current_attached_policies_arn_list.append(policy["PolicyArn"]) - - # If managed_policies has a single empty element we want to remove all attached policies - if purge_policies: - # Detach policies not present - for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)): - changed = True - if not module.check_mode: - try: - connection.detach_group_policy(GroupName=params["GroupName"], PolicyArn=policy_arn) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg=f"Couldn't detach policy from group {params['GroupName']}") - # If there are policies to adjust that aren't in the current list, then things have changed - # Otherwise the only changes were in purging above - if set(managed_policies) - set(current_attached_policies_arn_list): - changed = True - # If there are policies in managed_policies attach each policy - if managed_policies != [None] and not module.check_mode: - for policy_arn in managed_policies: - try: - connection.attach_group_policy(GroupName=params["GroupName"], PolicyArn=policy_arn) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg=f"Couldn't attach policy to group {params['GroupName']}") - - # Manage group memberships - try: - current_group_members = get_group(connection, module, params["GroupName"])["Users"] - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't get group {params['GroupName']}") - - current_group_members_list = [] - for member in current_group_members: - current_group_members_list.append(member["UserName"]) - - if not compare_group_members(current_group_members_list, users): - if purge_users: - for user in list(set(current_group_members_list) - set(users)): - # Ensure we mark things have changed if any user gets purged - changed = True - # Skip actions for check mode - if not module.check_mode: - try: - connection.remove_user_from_group(GroupName=params["GroupName"], UserName=user) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg=f"Couldn't remove user {user} from group {params['GroupName']}") - # If there are users to adjust that aren't in the current list, then things have changed - # Otherwise the only changes were in purging above - if set(users) - set(current_group_members_list): - changed = True - # Skip actions for check mode - if users != [None] and not module.check_mode: - for user in users: - try: - connection.add_user_to_group(GroupName=params["GroupName"], UserName=user) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg=f"Couldn't add user {user} to group {params['GroupName']}") - if module.check_mode: - module.exit_json(changed=changed) - - # Get the group again - try: - group = get_group(connection, module, params["GroupName"]) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't get group {params['GroupName']}") - - module.exit_json(changed=changed, iam_group=camel_dict_to_snake_dict(group)) - - -def destroy_group(connection, module): - params = dict() - params["GroupName"] = module.params.get("name") - - try: - group = get_group(connection, module, params["GroupName"]) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't get group {params['GroupName']}") - if group: - # Check mode means we would remove this group - if module.check_mode: - module.exit_json(changed=True) - - # Remove any attached policies otherwise deletion fails - try: - for policy in get_attached_policy_list(connection, module, params["GroupName"]): - connection.detach_group_policy(GroupName=params["GroupName"], PolicyArn=policy["PolicyArn"]) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, msg=f"Couldn't remove policy from group {params['GroupName']}") - - # Remove any users in the group otherwise deletion fails - current_group_members_list = [] - try: - current_group_members = get_group(connection, module, params["GroupName"])["Users"] - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't get group {params['GroupName']}") - for member in current_group_members: - current_group_members_list.append(member["UserName"]) - for user in current_group_members_list: - try: - connection.remove_user_from_group(GroupName=params["GroupName"], UserName=user) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't remove user {user} from group {params['GroupName']}") - - try: - connection.delete_group(**params) - except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: - module.fail_json_aws(e, f"Couldn't delete group {params['GroupName']}") - - else: - module.exit_json(changed=False) - - module.exit_json(changed=True) - - -@AWSRetry.exponential_backoff() -def get_group(connection, module, name): - try: - paginator = connection.get_paginator("get_group") - return paginator.paginate(GroupName=name).build_full_result() - except is_boto3_error_code("NoSuchEntity"): - return None - - -@AWSRetry.exponential_backoff() -def get_attached_policy_list(connection, module, name): - try: - paginator = connection.get_paginator("list_attached_group_policies") - return paginator.paginate(GroupName=name).build_full_result()["AttachedPolicies"] - except is_boto3_error_code("NoSuchEntity"): - return None - - -def main(): - argument_spec = dict( - name=dict(required=True), - managed_policies=dict(default=[], type="list", aliases=["managed_policy"], elements="str"), - users=dict(default=[], type="list", elements="str"), - state=dict(choices=["present", "absent"], required=True), - purge_users=dict(default=False, type="bool"), - purge_policies=dict(default=False, type="bool", aliases=["purge_policy", "purge_managed_policies"]), - ) - - module = AnsibleAWSModule( - argument_spec=argument_spec, - supports_check_mode=True, - ) - - connection = module.client("iam") - - state = module.params.get("state") - - if state == "present": - create_or_update_group(connection, module) - else: - destroy_group(connection, module) - - -if __name__ == "__main__": - main() diff --git a/plugins/modules/iam_policy.py b/plugins/modules/iam_policy.py index 16d12f058aa..53e11227120 100644 --- a/plugins/modules/iam_policy.py +++ b/plugins/modules/iam_policy.py @@ -12,7 +12,7 @@ description: - Allows uploading or removing inline IAM policies for IAM users, groups or roles. - To administer managed policies please see M(community.aws.iam_user), M(community.aws.iam_role), - M(amazon.aws.iam_group) and M(community.aws.iam_managed_policy) + M(community.aws.iam_group) and M(community.aws.iam_managed_policy) - This module was originally added to C(community.aws) in release 1.0.0. options: iam_type: @@ -61,7 +61,7 @@ # Advanced example, create two new groups and add a READ-ONLY policy to both # groups. - name: Create Two Groups, Mario and Luigi - amazon.aws.iam_group: + community.aws.iam_group: name: "{{ item }}" state: present loop: diff --git a/plugins/modules/iam_user.py b/plugins/modules/iam_user.py index 75e35ad5198..f4f1483cdde 100644 --- a/plugins/modules/iam_user.py +++ b/plugins/modules/iam_user.py @@ -11,7 +11,7 @@ short_description: Manage AWS IAM users description: - A module to manage AWS IAM users. - - The module does not manage groups that users belong to, groups memberships can be managed using M(amazon.aws.iam_group). + - The module does not manage groups that users belong to, groups memberships can be managed using M(community.aws.iam_group). - This module was originally added to C(community.aws) in release 1.0.0. author: - Josh Souza (@joshsouza) @@ -102,7 +102,7 @@ EXAMPLES = r""" # Note: These examples do not set authentication details, see the AWS Guide for details. # Note: This module does not allow management of groups that users belong to. -# Groups should manage their membership directly using amazon.aws.iam_group, +# Groups should manage their membership directly using community.aws.iam_group, # as users belong to them. - name: Create a user diff --git a/tests/integration/targets/iam_group/aliases b/tests/integration/targets/iam_group/aliases deleted file mode 100644 index 2da398045bd..00000000000 --- a/tests/integration/targets/iam_group/aliases +++ /dev/null @@ -1,7 +0,0 @@ -# reason: missing-policy -# It should be possible to test iam_groups by limiting which policies can be -# attached to the groups as well as which users can be added to the groups. -# Careful review is needed prior to adding this to the main CI. -unsupported - -cloud/aws diff --git a/tests/integration/targets/iam_group/defaults/main.yml b/tests/integration/targets/iam_group/defaults/main.yml deleted file mode 100644 index f5112b1a423..00000000000 --- a/tests/integration/targets/iam_group/defaults/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -test_user: '{{ resource_prefix }}-user' -test_group: '{{ resource_prefix }}-group' diff --git a/tests/integration/targets/iam_group/meta/main.yml b/tests/integration/targets/iam_group/meta/main.yml deleted file mode 100644 index 32cf5dda7ed..00000000000 --- a/tests/integration/targets/iam_group/meta/main.yml +++ /dev/null @@ -1 +0,0 @@ -dependencies: [] diff --git a/tests/integration/targets/iam_group/tasks/main.yml b/tests/integration/targets/iam_group/tasks/main.yml deleted file mode 100644 index a1240846cb8..00000000000 --- a/tests/integration/targets/iam_group/tasks/main.yml +++ /dev/null @@ -1,127 +0,0 @@ ---- -- name: set up aws connection info - module_defaults: - group/aws: - access_key: "{{ aws_access_key }}" - secret_key: "{{ aws_secret_key }}" - session_token: "{{ security_token | default(omit) }}" - region: "{{ aws_region }}" - collections: - - amazon.aws - block: - - name: ensure ansible user exists - iam_user: - name: '{{ test_user }}' - state: present - - - name: ensure group exists - iam_group: - name: '{{ test_group }}' - users: - - '{{ test_user }}' - state: present - register: iam_group - - - assert: - that: - - iam_group.iam_group.users - - iam_group is changed - - - name: add non existent user to group - iam_group: - name: '{{ test_group }}' - users: - - '{{ test_user }}' - - NonExistentUser - state: present - ignore_errors: yes - register: iam_group - - - name: assert that adding non existent user to group fails with helpful message - assert: - that: - - iam_group is failed - - iam_group.msg.startswith("Couldn't add user NonExistentUser to group {{ test_group }}") - - - name: remove a user - iam_group: - name: '{{ test_group }}' - purge_users: True - users: [] - state: present - register: iam_group - - - assert: - that: - - iam_group is changed - - not iam_group.iam_group.users - - - name: re-remove a user (no change) - iam_group: - name: '{{ test_group }}' - purge_users: True - users: [] - state: present - register: iam_group - - - assert: - that: - - iam_group is not changed - - not iam_group.iam_group.users - - - name: Add the user again - iam_group: - name: '{{ test_group }}' - users: - - '{{ test_user }}' - state: present - register: iam_group - - - assert: - that: - - iam_group is changed - - iam_group.iam_group.users - - - name: Re-add the user - iam_group: - name: '{{ test_group }}' - users: - - '{{ test_user }}' - state: present - register: iam_group - - - assert: - that: - - iam_group is not changed - - iam_group.iam_group.users - - - name: remove group - iam_group: - name: '{{ test_group }}' - state: absent - register: iam_group - - - assert: - that: - - iam_group is changed - - - name: re-remove group - iam_group: - name: '{{ test_group }}' - state: absent - register: iam_group - - - assert: - that: - - iam_group is not changed - - always: - - name: remove group - iam_group: - name: '{{ test_group }}' - state: absent - - - name: remove ansible user - iam_user: - name: '{{ test_user }}' - state: absent