Improve consistency of IAM_{role,user,group} behaviour (#64258)

* iam_user: use AnsibleAWSModule.client to fetch connection rather than C&P code

* iam_role: Add deprecation warning so we can switch purge_polices default behaviour from true to false

* iam_user/role/group: Rename 'managed_policy' and 'purge_policy'

Rename from singluar to plural (we accept a *list* of policies), and add aliases for the old values.

* Cleanup documentation

* Changelog
pull/65160/head
Mark Chappell 5 years ago committed by Jill R
parent 784e507671
commit 6e652ae6df

@ -0,0 +1,5 @@
deprecated_features:
- 'iam_role: The default value of the purge_policies has been deprecated and will change from true to false in Ansible 2.14'
minor_changes:
- 'iam_role, iam_user and iam_group: the managed_policy option has been renamed to managed_policies (with an alias added)'
- 'iam_role, iam_user and iam_group: the purge_policy option has been renamed to purge_policies (with an alias added)'

@ -58,7 +58,7 @@ The following functionality will be removed in Ansible 2.14. Please update updat
* The :ref:`openssl_csr <openssl_csr_module>` module's option ``version`` no longer supports values other than ``1`` (the current only standardized CSR version). * The :ref:`openssl_csr <openssl_csr_module>` module's option ``version`` no longer supports values other than ``1`` (the current only standardized CSR version).
* :ref:`docker_container <docker_container_module>`: the ``trust_image_content`` option will be removed. It has always been ignored by the module. * :ref:`docker_container <docker_container_module>`: the ``trust_image_content`` option will be removed. It has always been ignored by the module.
* :ref:`iam_managed_policy <iam_managed_policy_module>`: the ``fail_on_delete`` option wil be removed. It has always been ignored by the module. * :ref:`iam_managed_policy <iam_managed_policy_module>`: the ``fail_on_delete`` option will be removed. It has always been ignored by the module.
* :ref:`s3_lifecycle <s3_lifecycle_module>`: the ``requester_pays`` option will be removed. It has always been ignored by the module. * :ref:`s3_lifecycle <s3_lifecycle_module>`: the ``requester_pays`` option will be removed. It has always been ignored by the module.
* :ref:`s3_sync <s3_sync_module>`: the ``retries`` option will be removed. It has always been ignored by the module. * :ref:`s3_sync <s3_sync_module>`: the ``retries`` option will be removed. It has always been ignored by the module.
* The return values ``err`` and ``out`` of :ref:`docker_stack <docker_stack_module>` have been deprecated. Use ``stdout`` and ``stderr`` from now on instead. * The return values ``err`` and ``out`` of :ref:`docker_stack <docker_stack_module>` have been deprecated. Use ``stdout`` and ``stderr`` from now on instead.
@ -76,6 +76,7 @@ The following functionality will change in Ansible 2.14. Please update update yo
* The :ref:`docker_container <docker_container_module>` module has a new option, ``container_default_behavior``, whose default value will change from ``compatibility`` to ``no_defaults``. Set to an explicit value to avoid deprecation warnings. * The :ref:`docker_container <docker_container_module>` module has a new option, ``container_default_behavior``, whose default value will change from ``compatibility`` to ``no_defaults``. Set to an explicit value to avoid deprecation warnings.
* :ref:`iam_policy <iam_policy_module>`: the default value for the ``skip_duplicates`` option will change from ``true`` to ``false``. To maintain the existing behavior explicitly set it to ``true``. * :ref:`iam_policy <iam_policy_module>`: the default value for the ``skip_duplicates`` option will change from ``true`` to ``false``. To maintain the existing behavior explicitly set it to ``true``.
* :ref:`iam_role <iam_role_module>`: the ``purge_policies`` option (also know as ``purge_policy``) default value will change from ``true`` to ``false``
The following modules will be removed in Ansible 2.14. Please update your playbooks accordingly. The following modules will be removed in Ansible 2.14. Please update your playbooks accordingly.

@ -26,7 +26,7 @@ DOCUMENTATION = '''
module: iam_group module: iam_group
short_description: Manage AWS IAM groups short_description: Manage AWS IAM groups
description: description:
- Manage AWS IAM groups - Manage AWS IAM groups.
version_added: "2.4" version_added: "2.4"
author: author:
- Nick Aslanidis (@naslanidis) - Nick Aslanidis (@naslanidis)
@ -37,31 +37,36 @@ options:
- The name of the group to create. - The name of the group to create.
required: true required: true
type: str type: str
managed_policy: managed_policies:
description: description:
- A list of managed policy ARNs or friendly names to attach to the role. To embed an inline policy, use M(iam_policy). - A list of managed policy ARNs or friendly names to attach to the role.
- To embed an inline policy, use M(iam_policy).
required: false required: false
type: list type: list
elements: str
aliases: ['managed_policy']
users: users:
description: description:
- A list of existing users to add as members of the group. - A list of existing users to add as members of the group.
required: false required: false
type: list type: list
elements: str
state: state:
description: description:
- Create or remove the IAM group - Create or remove the IAM group.
required: true required: true
choices: [ 'present', 'absent' ] choices: [ 'present', 'absent' ]
type: str type: str
purge_policy: purge_policies:
description: description:
- Detach policy which not included in managed_policy list - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
required: false required: false
default: false default: false
type: bool type: bool
aliases: ['purge_policy', 'purge_managed_policies']
purge_users: purge_users:
description: description:
- Detach users which not included in users list - When I(purge_users=true) users which are not included in I(users) will be detached.
required: false required: false
default: false default: false
type: bool type: bool
@ -82,14 +87,14 @@ EXAMPLES = '''
# Create a group and attach a managed policy using its ARN # Create a group and attach a managed policy using its ARN
- iam_group: - iam_group:
name: testgroup1 name: testgroup1
managed_policy: managed_policies:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess - arn:aws:iam::aws:policy/AmazonSNSFullAccess
state: present state: present
# Create a group with users as members and attach a managed policy using its ARN # Create a group with users as members and attach a managed policy using its ARN
- iam_group: - iam_group:
name: testgroup1 name: testgroup1
managed_policy: managed_policies:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess - arn:aws:iam::aws:policy/AmazonSNSFullAccess
users: users:
- test_user1 - test_user1
@ -100,12 +105,12 @@ EXAMPLES = '''
- iam_group: - iam_group:
name: testgroup1 name: testgroup1
state: present state: present
purge_policy: true purge_policies: true
# Remove all group members from an existing group # Remove all group members from an existing group
- iam_group: - iam_group:
name: testgroup1 name: testgroup1
managed_policy: managed_policies:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess - arn:aws:iam::aws:policy/AmazonSNSFullAccess
purge_users: true purge_users: true
state: present state: present
@ -233,10 +238,10 @@ def create_or_update_group(connection, module):
params = dict() params = dict()
params['GroupName'] = module.params.get('name') params['GroupName'] = module.params.get('name')
managed_policies = module.params.get('managed_policy') managed_policies = module.params.get('managed_policies')
users = module.params.get('users') users = module.params.get('users')
purge_users = module.params.get('purge_users') purge_users = module.params.get('purge_users')
purge_policy = module.params.get('purge_policy') purge_policies = module.params.get('purge_policies')
changed = False changed = False
if managed_policies: if managed_policies:
managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies) managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
@ -267,7 +272,7 @@ def create_or_update_group(connection, module):
current_attached_policies_arn_list.append(policy['PolicyArn']) current_attached_policies_arn_list.append(policy['PolicyArn'])
# If managed_policies has a single empty element we want to remove all attached policies # If managed_policies has a single empty element we want to remove all attached policies
if purge_policy: if purge_policies:
# Detach policies not present # Detach policies not present
for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)): for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)):
changed = True changed = True
@ -408,11 +413,11 @@ def main():
argument_spec = dict( argument_spec = dict(
name=dict(required=True), name=dict(required=True),
managed_policy=dict(default=[], type='list'), managed_policies=dict(default=[], type='list', aliases=['managed_policy']),
users=dict(default=[], type='list'), users=dict(default=[], type='list'),
state=dict(choices=['present', 'absent'], required=True), state=dict(choices=['present', 'absent'], required=True),
purge_users=dict(default=False, type='bool'), purge_users=dict(default=False, type='bool'),
purge_policy=dict(default=False, type='bool') purge_policies=dict(default=False, type='bool', aliases=['purge_policy', 'purge_managed_policies'])
) )
module = AnsibleAWSModule( module = AnsibleAWSModule(

@ -14,7 +14,7 @@ DOCUMENTATION = '''
module: iam_role module: iam_role
short_description: Manage AWS IAM roles short_description: Manage AWS IAM roles
description: description:
- Manage AWS IAM roles - Manage AWS IAM roles.
version_added: "2.3" version_added: "2.3"
author: "Rob White (@wimnat)" author: "Rob White (@wimnat)"
options: options:
@ -30,15 +30,15 @@ options:
type: str type: str
description: description:
description: description:
- Provide a description of the new role. - Provides a description of the role.
version_added: "2.5" version_added: "2.5"
type: str type: str
boundary: boundary:
description: description:
- The ARN of an IAM managed policy to use to restrict the permissions this role can pass on to IAM roles/users that it creates. - The ARN of an IAM managed policy to use to restrict the permissions this role can pass on to IAM roles/users that it creates.
- Boundaries cannot be set on Instance Profiles, so if this option is specified then I(create_instance_profile) must be false. - Boundaries cannot be set on Instance Profiles, as such if this option is specified then I(create_instance_profile) must be C(false).
- This is intended for roles/users that have permissions to create new IAM objects. - This is intended for roles/users that have permissions to create new IAM objects.
- For more information on boundaries, see U(https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html) - For more information on boundaries, see U(https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html).
- Requires botocore 1.10.57 or above. - Requires botocore 1.10.57 or above.
aliases: [boundary_policy_arn] aliases: [boundary_policy_arn]
version_added: "2.7" version_added: "2.7"
@ -46,13 +46,14 @@ options:
assume_role_policy_document: assume_role_policy_document:
description: description:
- The trust relationship policy document that grants an entity permission to assume the role. - The trust relationship policy document that grants an entity permission to assume the role.
- "This parameter is required when I(state=present)." - This parameter is required when I(state=present).
type: json type: json
managed_policy: managed_policies:
description: description:
- A list of managed policy ARNs or, since Ansible 2.4, a list of either managed policy ARNs or friendly names. - A list of managed policy ARNs or, since Ansible 2.4, a list of either managed policy ARNs or friendly names.
To embed an inline policy, use M(iam_policy). To remove existing policies, use an empty list item. - To remove all policies set I(purge_polices=true) and I(managed_policies=[None]).
aliases: [ managed_policies ] - To embed an inline policy, use M(iam_policy).
aliases: ['managed_policy']
type: list type: list
max_session_duration: max_session_duration:
description: description:
@ -62,10 +63,11 @@ options:
type: int type: int
purge_policies: purge_policies:
description: description:
- Detaches any managed policies not listed in the I(managed_policy) option. Set to false if you want to attach policies elsewhere. - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
default: true - By default I(purge_policies=true). In Ansible 2.14 this will be changed to I(purge_policies=false).
version_added: "2.5" version_added: "2.5"
type: bool type: bool
aliases: ['purge_policy', 'purge_managed_policies']
state: state:
description: description:
- Create or remove the IAM role. - Create or remove the IAM role.
@ -80,8 +82,8 @@ options:
type: bool type: bool
delete_instance_profile: delete_instance_profile:
description: description:
- When deleting a role will also delete the instance profile created with - When I(delete_instance_profile=true) and I(state=absent) deleting a role will also delete the instance
the same name as the role. profile created with the same I(name) as the role.
- Only applies when I(state=absent). - Only applies when I(state=absent).
default: false default: false
version_added: "2.10" version_added: "2.10"
@ -119,14 +121,14 @@ EXAMPLES = '''
iam_role: iam_role:
name: mynewrole name: mynewrole
assume_role_policy_document: "{{ lookup('file','policy.json') }}" assume_role_policy_document: "{{ lookup('file','policy.json') }}"
managed_policy: managed_policies:
- arn:aws:iam::aws:policy/PowerUserAccess - arn:aws:iam::aws:policy/PowerUserAccess
- name: Keep the role created above but remove all managed policies - name: Keep the role created above but remove all managed policies
iam_role: iam_role:
name: mynewrole name: mynewrole
assume_role_policy_document: "{{ lookup('file','policy.json') }}" assume_role_policy_document: "{{ lookup('file','policy.json') }}"
managed_policy: [] managed_policies: []
- name: Delete the role - name: Delete the role
iam_role: iam_role:
@ -276,7 +278,10 @@ def create_or_update_role(connection, module):
params['Description'] = module.params.get('description') params['Description'] = module.params.get('description')
if module.params.get('boundary') is not None: if module.params.get('boundary') is not None:
params['PermissionsBoundary'] = module.params.get('boundary') params['PermissionsBoundary'] = module.params.get('boundary')
managed_policies = module.params.get('managed_policy') managed_policies = module.params.get('managed_policies')
purge_policies = module.params.get('purge_policies')
if purge_policies is None:
purge_policies = True
create_instance_profile = module.params.get('create_instance_profile') create_instance_profile = module.params.get('create_instance_profile')
if managed_policies: if managed_policies:
managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies) managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
@ -320,7 +325,7 @@ def create_or_update_role(connection, module):
current_attached_policies_arn_list = [policy['PolicyArn'] for policy in current_attached_policies] current_attached_policies_arn_list = [policy['PolicyArn'] for policy in current_attached_policies]
# If a single empty list item then all managed policies to be removed # If a single empty list item then all managed policies to be removed
if len(managed_policies) == 1 and not managed_policies[0] and module.params.get('purge_policies'): if len(managed_policies) == 1 and not managed_policies[0] and purge_policies:
# Detach policies not present # Detach policies not present
if remove_policies(connection, module, set(current_attached_policies_arn_list) - set(managed_policies), params): if remove_policies(connection, module, set(current_attached_policies_arn_list) - set(managed_policies), params):
@ -329,7 +334,7 @@ def create_or_update_role(connection, module):
# Make a list of the ARNs from the attached policies # Make a list of the ARNs from the attached policies
# Detach roles not defined in task # Detach roles not defined in task
if module.params.get('purge_policies'): if purge_policies:
if remove_policies(connection, module, set(current_attached_policies_arn_list) - set(managed_policies), params): if remove_policies(connection, module, set(current_attached_policies_arn_list) - set(managed_policies), params):
changed = True changed = True
@ -565,14 +570,14 @@ def main():
name=dict(type='str', required=True), name=dict(type='str', required=True),
path=dict(type='str', default="/"), path=dict(type='str', default="/"),
assume_role_policy_document=dict(type='json'), assume_role_policy_document=dict(type='json'),
managed_policy=dict(type='list', aliases=['managed_policies']), managed_policies=dict(type='list', aliases=['managed_policy']),
max_session_duration=dict(type='int'), max_session_duration=dict(type='int'),
state=dict(type='str', choices=['present', 'absent'], default='present'), state=dict(type='str', choices=['present', 'absent'], default='present'),
description=dict(type='str'), description=dict(type='str'),
boundary=dict(type='str', aliases=['boundary_policy_arn']), boundary=dict(type='str', aliases=['boundary_policy_arn']),
create_instance_profile=dict(type='bool', default=True), create_instance_profile=dict(type='bool', default=True),
delete_instance_profile=dict(type='bool', default=False), delete_instance_profile=dict(type='bool', default=False),
purge_policies=dict(type='bool', default=True), purge_policies=dict(type='bool', aliases=['purge_policy', 'purge_managed_policies']),
tags=dict(type='dict'), tags=dict(type='dict'),
purge_tags=dict(type='bool', default=True), purge_tags=dict(type='bool', default=True),
) )
@ -580,6 +585,10 @@ def main():
required_if=[('state', 'present', ['assume_role_policy_document'])], required_if=[('state', 'present', ['assume_role_policy_document'])],
supports_check_mode=True) supports_check_mode=True)
if module.params.get('purge_policies') is None:
module.deprecate('In Ansible 2.14 the default value of purge_policies will change from true to false.'
' To maintain the existing behaviour explicity set purge_policies=true', version='2.14')
if module.params.get('boundary'): if module.params.get('boundary'):
if module.params.get('create_instance_profile'): if module.params.get('create_instance_profile'):
module.fail_json(msg="When using a boundary policy, `create_instance_profile` must be set to `false`.") module.fail_json(msg="When using a boundary policy, `create_instance_profile` must be set to `false`.")

@ -14,7 +14,7 @@ DOCUMENTATION = '''
module: iam_user module: iam_user
short_description: Manage AWS IAM users short_description: Manage AWS IAM users
description: description:
- Manage AWS IAM users - Manage AWS IAM users.
version_added: "2.5" version_added: "2.5"
author: Josh Souza (@joshsouza) author: Josh Souza (@joshsouza)
options: options:
@ -23,23 +23,26 @@ options:
- The name of the user to create. - The name of the user to create.
required: true required: true
type: str type: str
managed_policy: managed_policies:
description: description:
- A list of managed policy ARNs or friendly names to attach to the user. To embed an inline policy, use M(iam_policy). - A list of managed policy ARNs or friendly names to attach to the user.
- To embed an inline policy, use M(iam_policy).
required: false required: false
type: list type: list
aliases: ['managed_policy']
state: state:
description: description:
- Create or remove the IAM user - Create or remove the IAM user.
required: true required: true
choices: [ 'present', 'absent' ] choices: [ 'present', 'absent' ]
type: str type: str
purge_policy: purge_policies:
description: description:
- Detach policies which are not included in managed_policy list - When I(purge_policies=true) any managed policies not listed in I(managed_policies) will be detatched.
required: false required: false
default: false default: false
type: bool type: bool
aliases: ['purge_policy', 'purge_managed_policies']
requirements: [ botocore, boto3 ] requirements: [ botocore, boto3 ]
extends_documentation_fragment: extends_documentation_fragment:
- aws - aws
@ -60,7 +63,7 @@ EXAMPLES = '''
# Create a user and attach a managed policy using its ARN # Create a user and attach a managed policy using its ARN
- iam_user: - iam_user:
name: testuser1 name: testuser1
managed_policy: managed_policies:
- arn:aws:iam::aws:policy/AmazonSNSFullAccess - arn:aws:iam::aws:policy/AmazonSNSFullAccess
state: present state: present
@ -68,7 +71,7 @@ EXAMPLES = '''
- iam_user: - iam_user:
name: testuser1 name: testuser1
state: present state: present
purge_policy: true purge_policies: true
# Delete the user # Delete the user
- iam_user: - iam_user:
@ -157,8 +160,8 @@ def create_or_update_user(connection, module):
params = dict() params = dict()
params['UserName'] = module.params.get('name') params['UserName'] = module.params.get('name')
managed_policies = module.params.get('managed_policy') managed_policies = module.params.get('managed_policies')
purge_policy = module.params.get('purge_policy') purge_policies = module.params.get('purge_policies')
changed = False changed = False
if managed_policies: if managed_policies:
managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies) managed_policies = convert_friendly_names_to_arns(connection, module, managed_policies)
@ -189,7 +192,7 @@ def create_or_update_user(connection, module):
current_attached_policies_arn_list.append(policy['PolicyArn']) current_attached_policies_arn_list.append(policy['PolicyArn'])
# If managed_policies has a single empty element we want to remove all attached policies # If managed_policies has a single empty element we want to remove all attached policies
if purge_policy: if purge_policies:
# Detach policies not present # Detach policies not present
for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)): for policy_arn in list(set(current_attached_policies_arn_list) - set(managed_policies)):
changed = True changed = True
@ -342,26 +345,19 @@ def delete_user_login_profile(connection, module, user_name):
def main(): def main():
argument_spec = ec2_argument_spec() argument_spec = dict(
argument_spec.update(
dict(
name=dict(required=True, type='str'), name=dict(required=True, type='str'),
managed_policy=dict(default=[], type='list'), managed_policies=dict(default=[], type='list', aliases=['managed_policy']),
state=dict(choices=['present', 'absent'], required=True), state=dict(choices=['present', 'absent'], required=True),
purge_policy=dict(default=False, type='bool') purge_policies=dict(default=False, type='bool', aliases=['purge_policy', 'purge_managed_policies'])
)
) )
module = AnsibleAWSModule( module = AnsibleAWSModule(
argument_spec=argument_spec, argument_spec=argument_spec,
supports_check_mode=True supports_check_mode=True
) )
if not HAS_BOTO3:
module.fail_json(msg='boto3 required for this module')
region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
connection = boto3_conn(module, conn_type='client', resource='iam', region=region, endpoint=ec2_url, **aws_connect_params) connection = module.client('iam')
state = module.params.get("state") state = module.params.get("state")

Loading…
Cancel
Save