New module: iam_policy_info (#62955)

* iam_policy: (integration tests) migrate to module_defaults

* iam_policy: (integration tests) Rework iam_policy integration tests

* iam_policy_info: Add new module and add iam_policy_info tests to iam_policy integration tests
This commit is contained in:
Mark Chappell 2019-10-23 22:04:25 +02:00 committed by Jill R
parent 18b9ce8b82
commit bd6d4b5b3a
7 changed files with 1346 additions and 285 deletions

View file

@ -455,6 +455,8 @@ groupings:
- aws - aws
iam_policy: iam_policy:
- aws - aws
iam_policy_info:
- aws
iam_role: iam_role:
- aws - aws
iam_role_facts: iam_role_facts:

View file

@ -0,0 +1,230 @@
#!/usr/bin/python
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['stableinterface'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: iam_policy_info
short_description: Retrieve inline IAM policies for users, groups, and roles
description:
- Supports fetching of inline IAM policies for IAM users, groups and roles.
version_added: "2.10"
options:
iam_type:
description:
- Type of IAM resource you wish to retrieve inline policies for.
required: yes
choices: [ "user", "group", "role"]
type: str
iam_name:
description:
- Name of IAM resource you wish to retrieve inline policies for. In other words, the user name, group name or role name.
required: yes
type: str
policy_name:
description:
- Name of a specific IAM inline policy you with to retrieve.
required: no
type: str
author:
- Mark Chappell (@tremble)
extends_documentation_fragment:
- aws
- ec2
'''
EXAMPLES = '''
# Describe all inline IAM policies on an IAM User
- iam_policy_info:
iam_type: user
iam_name: example_user
# Describe a specific inline policy on an IAM Role
- iam_policy_info:
iam_type: role
iam_name: example_role
policy_name: example_policy
'''
RETURN = '''
policies:
description: A list containing the matching IAM inline policy names and their data
returned: success
type: complex
contains:
policy_name:
description: The Name of the inline policy
returned: success
type: str
policy_document:
description: The JSON document representing the inline IAM policy
returned: success
type: list
policy_names:
description: A list of matching names of the IAM inline policies on the queried object
returned: success
type: list
all_policy_names:
description: A list of names of all of the IAM inline policies on the queried object
returned: success
type: list
'''
import json
try:
from botocore.exceptions import BotoCoreError, ClientError
except ImportError:
pass
from ansible.module_utils.aws.core import AnsibleAWSModule
from ansible.module_utils.six import string_types
class PolicyError(Exception):
pass
class Policy:
def __init__(self, client, name, policy_name):
self.client = client
self.name = name
self.policy_name = policy_name
self.changed = False
@staticmethod
def _iam_type():
return ''
def _list(self, name):
return {}
def list(self):
return self._list(self.name).get('PolicyNames', [])
def _get(self, name, policy_name):
return '{}'
def get(self, policy_name):
return self._get(self.name, policy_name)['PolicyDocument']
def get_all(self):
policies = list()
for policy in self.list():
policies.append({"policy_name": policy, "policy_document": self.get(policy)})
return policies
def run(self):
policy_list = self.list()
ret_val = {
'changed': False,
self._iam_type() + '_name': self.name,
'all_policy_names': policy_list
}
if self.policy_name is None:
ret_val.update(policies=self.get_all())
ret_val.update(policy_names=policy_list)
elif self.policy_name in policy_list:
ret_val.update(policies=[{
"policy_name": self.policy_name,
"policy_document": self.get(self.policy_name)}])
ret_val.update(policy_names=[self.policy_name])
return ret_val
class UserPolicy(Policy):
@staticmethod
def _iam_type():
return 'user'
def _list(self, name):
return self.client.list_user_policies(UserName=name)
def _get(self, name, policy_name):
return self.client.get_user_policy(UserName=name, PolicyName=policy_name)
class RolePolicy(Policy):
@staticmethod
def _iam_type():
return 'role'
def _list(self, name):
return self.client.list_role_policies(RoleName=name)
def _get(self, name, policy_name):
return self.client.get_role_policy(RoleName=name, PolicyName=policy_name)
class GroupPolicy(Policy):
@staticmethod
def _iam_type():
return 'group'
def _list(self, name):
return self.client.list_group_policies(GroupName=name)
def _get(self, name, policy_name):
return self.client.get_group_policy(GroupName=name, PolicyName=policy_name)
def main():
argument_spec = dict(
iam_type=dict(required=True, choices=['user', 'group', 'role']),
iam_name=dict(required=True),
policy_name=dict(default=None, required=False),
)
module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)
args = dict(
client=module.client('iam'),
name=module.params.get('iam_name'),
policy_name=module.params.get('policy_name'),
)
iam_type = module.params.get('iam_type')
try:
if iam_type == 'user':
policy = UserPolicy(**args)
elif iam_type == 'role':
policy = RolePolicy(**args)
elif iam_type == 'group':
policy = GroupPolicy(**args)
module.exit_json(**(policy.run()))
except (BotoCoreError, ClientError) as e:
if e.response['Error']['Code'] == 'NoSuchEntity':
module.exit_json(changed=False, msg=e.response['Error']['Message'])
module.fail_json_aws(e)
except PolicyError as e:
module.fail_json(msg=str(e))
if __name__ == '__main__':
main()

View file

@ -1,2 +1,3 @@
iam_policy_info
cloud/aws cloud/aws
unsupported unsupported

View file

@ -1,5 +1,6 @@
--- ---
iam_user_name: '{{resource_prefix}}' iam_name: '{{resource_prefix}}'
iam_role_name: '{{resource_prefix}}' iam_policy_name_a: '{{resource_prefix}}-document-a'
iam_group_name: '{{resource_prefix}}' iam_policy_name_b: '{{resource_prefix}}-document-b'
iam_policy_name: '{{resource_prefix}}' iam_policy_name_c: '{{resource_prefix}}-json-a'
iam_policy_name_d: '{{resource_prefix}}-json-b'

View file

@ -0,0 +1,11 @@
{
"Id": "MyOtherId",
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Action": "*",
"Resource": "*"
}
]
}

View file

@ -1,323 +1,95 @@
--- ---
- block: - name: 'Run integration tests for IAM (inline) Policy management'
# ============================================================ module_defaults:
- name: set up aws connection info group/aws:
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}" aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}" aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}" security_token: "{{ security_token | default(omit) }}"
region: "{{ aws_region }}" region: "{{ aws_region }}"
no_log: yes block:
# ============================================================ # ============================================================
- name: Create a temporary folder for the policies - name: Create a temporary folder for the policies
tempfile: tempfile:
state: directory state: directory
register: tmpdir register: tmpdir
# ============================================================
- name: Copy over policy - name: Copy over policy
copy: copy:
src: no_access.json src: no_access.json
dest: "{{ tmpdir.path }}" dest: "{{ tmpdir.path }}"
# ============================================================
- name: Copy over other policy - name: Copy over other policy
copy: copy:
src: no_access_with_id.json src: no_access_with_id.json
dest: "{{ tmpdir.path }}" dest: "{{ tmpdir.path }}"
- name: Copy over other policy
copy:
src: no_access_with_second_id.json
dest: "{{ tmpdir.path }}"
# ============================================================ # ============================================================
- name: Create user for tests - name: Create user for tests
iam_user: iam_user:
name: "{{ iam_user_name }}"
state: present state: present
<<: *aws_connection_info name: "{{ iam_name }}"
# ============================================================ register: result
- name: Ensure user was created
assert:
that:
- result is changed
- name: Create role for tests - name: Create role for tests
iam_role: iam_role:
name: "{{ iam_role_name }}"
assume_role_policy_document: "{{ lookup('file','no_trust.json') }}"
state: present state: present
<<: *aws_connection_info name: "{{ iam_name }}"
# ============================================================ assume_role_policy_document: "{{ lookup('file','no_trust.json') }}"
register: result
- name: Ensure role was created
assert:
that:
- result is changed
- name: Create group for tests - name: Create group for tests
iam_group: iam_group:
name: "{{ iam_group_name }}"
state: present state: present
<<: *aws_connection_info name: "{{ iam_name }}"
# ============================================================
- name: Create policy for user
iam_policy:
iam_type: user
iam_name: "{{ iam_user_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access.json"
<<: *aws_connection_info
register: result register: result
# ============================================================ - name: Ensure group was created
- name: Assert policy was added for user
assert: assert:
that: that:
- result.changed == True - result is changed
- result.policies == ["{{ iam_policy_name }}"]
- result.user_name == "{{ iam_user_name }}"
# ============================================================ # ============================================================
- name: Update policy for user
iam_policy: - name: Run tests for each type of object
iam_type: user include_tasks: object.yml
iam_name: "{{ iam_user_name }}" loop_control:
policy_name: "{{ iam_policy_name }}" loop_var: iam_type
state: present with_items:
policy_document: "{{ tmpdir.path }}/no_access_with_id.json" - user
<<: *aws_connection_info - group
register: result - role
# ============================================================
- name: Assert policy was updated for user
assert:
that:
- result.changed == True
# ============================================================
- name: Update policy for user with same policy
iam_policy:
iam_type: user
iam_name: "{{ iam_user_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access_with_id.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy did not change for user
assert:
that:
- result.changed == False
# ============================================================
- name: Create policy for user using policy_json
iam_policy:
iam_type: user
iam_name: "{{ iam_user_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_json: "{{ lookup('file', '{{ tmpdir.path }}/no_access.json') }}"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was added for user
assert:
that:
- result.changed == True
- result.policies == ["{{ iam_policy_name }}"]
- result.user_name == "{{ iam_user_name }}"
# ============================================================
- name: Create policy for role
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was added for role
assert:
that:
- result.changed == True
- result.policies == ["{{ iam_policy_name }}"]
- result.role_name == "{{ iam_role_name }}"
# ============================================================
- name: Update policy for role
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access_with_id.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was updated for role
assert:
that:
- result.changed == True
# ============================================================
- name: Update policy for role with same policy
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access_with_id.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy did not change for role
assert:
that:
- result.changed == False
# ============================================================
- name: Create policy for role using policy_json
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_json: "{{ lookup('file', '{{ tmpdir.path }}/no_access.json') }}"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was added for role
assert:
that:
- result.changed == True
- result.policies == ["{{ iam_policy_name }}"]
- result.role_name == "{{ iam_role_name }}"
# ============================================================
- name: Create policy for group
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was added for group
assert:
that:
- result.changed == True
- result.policies == ["{{ iam_policy_name }}"]
- result.group_name == "{{ iam_group_name }}"
# ============================================================
- name: Update policy for group
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access_with_id.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was updated for group
assert:
that:
- result.changed == True
# ============================================================
- name: Update policy for group with same policy
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_document: "{{ tmpdir.path }}/no_access_with_id.json"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy did not change for group
assert:
that:
- result.changed == False
# ============================================================
- name: Create policy for group using policy_json
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: present
policy_json: "{{ lookup('file', '{{ tmpdir.path }}/no_access.json') }}"
<<: *aws_connection_info
register: result
# ============================================================
- name: Assert policy was added for group
assert:
that:
- result.changed == True
- result.policies == ["{{ iam_policy_name }}"]
- result.group_name == "{{ iam_group_name }}"
# ============================================================
- name: Delete policy for user
iam_policy:
iam_type: user
iam_name: "{{ iam_user_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
- assert:
that:
- result.changed == True
# ============================================================
- name: Delete policy for role
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
- assert:
that:
- result.changed == True
# ============================================================
- name: Delete policy for group
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
- assert:
that:
- result.changed == True
# ============================================================ # ============================================================
always: always:
# ============================================================ # ============================================================
- name: Delete policy for user - name: Remove user
iam_policy:
iam_type: user
iam_name: "{{ iam_user_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes
# ============================================================
- name: Delete user for tests
iam_user: iam_user:
name: "{{ iam_user_name }}"
state: absent state: absent
<<: *aws_connection_info name: "{{ iam_name }}"
ignore_errors: yes ignore_errors: yes
# ============================================================
- name: Delete policy for role - name: Remove role
iam_policy:
iam_type: role
iam_name: "{{ iam_role_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes
# ============================================================
- name: Delete role for tests
iam_role: iam_role:
name: "{{ iam_role_name }}"
state: absent state: absent
<<: *aws_connection_info name: "{{ iam_name }}"
ignore_errors: yes ignore_errors: yes
# ============================================================
- name: Delete policy for group - name: Remove group
iam_policy:
iam_type: group
iam_name: "{{ iam_group_name }}"
policy_name: "{{ iam_policy_name }}"
state: absent
<<: *aws_connection_info
ignore_errors: yes
# ============================================================
- name: Delete group for tests
iam_group: iam_group:
name: "{{ iam_group_name }}"
state: absent state: absent
<<: *aws_connection_info name: "{{ iam_name }}"
ignore_errors: yes ignore_errors: yes
# ============================================================ # ============================================================
- name: Delete temporary folder containing the policies - name: Delete temporary folder containing the policies
file: file:

File diff suppressed because it is too large Load diff