[cloud] New iam_role_facts module (#32874)

* Add iam_role_facts module

Provide information about IAM roles

* Improve path prefix handling

Add preceding or trailing `/` if not already present
This commit is contained in:
Will Thames 2017-12-13 03:19:53 +10:00 committed by Ryan Brown
parent 1bb974a917
commit c27ded6bbc

View file

@ -0,0 +1,205 @@
#!/usr/bin/python
# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'certified'}
DOCUMENTATION = '''
---
module: iam_role_facts
short_description: Gather information on IAM roles
description:
- Gathers information about IAM roles
version_added: "2.5"
requirements: [ boto3 ]
author:
- "Will Thames (@willthames)"
options:
name:
description:
- Name of a role to search for
- Mutually exclusive with C(prefix)
required: false
default: None
aliases:
- role_name
path_prefix:
description:
- Prefix of role I(path) to restrict IAM role search for
- Mutually exclusive with C(name)
required: false
default: None
extends_documentation_fragment:
- aws
'''
EXAMPLES = '''
# find all existing IAM roles
- iam_role_facts:
register: result
# describe a single role
- iam_role_facts:
name: MyIAMRole
# describe all roles matching a path prefix
- iam_role_facts:
path_prefix: /application/path
'''
RETURN = '''
iam_roles:
description: List of IAM roles
returned: always
type: complex
contains:
arn:
description: Amazon Resource Name for IAM role
returned: always
type: string
sample: arn:aws:iam::123456789012:role/AnsibleTestRole
assume_role_policy_document:
description: Policy Document describing what can assume the role
returned: always
type: string
create_date:
description: Date IAM role was created
returned: always
type: string
sample: '2017-10-23T00:05:08+00:00'
inline_policies:
description: List of names of inline policies
returned: always
type: list
sample: []
managed_policies:
description: List of attached managed policies
returned: always
type: complex
contains:
policy_arn:
description: Amazon Resource Name for the policy
returned: always
type: string
sample: arn:aws:iam::123456789012:policy/AnsibleTestEC2Policy
policy_name:
description: Name of managed policy
returned: always
type: string
sample: AnsibleTestEC2Policy
path:
description: Path of role
returned: always
type: string
sample: /
role_id:
description: Amazon Identifier for the role
returned: always
type: string
sample: AROAII7ABCD123456EFGH
role_name:
description: Name of the role
returned: always
type: string
sample: AnsibleTestRole
'''
try:
import botocore
except ImportError:
pass # caught by AnsibleAWSModule
from ansible.module_utils.aws.core import AnsibleAWSModule
from ansible.module_utils.ec2 import boto3_conn, get_aws_connection_info, ec2_argument_spec, AWSRetry
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
@AWSRetry.exponential_backoff()
def list_iam_roles_with_backoff(client, **kwargs):
paginator = client.get_paginator('list_roles')
return paginator.paginate(**kwargs).build_full_result()
@AWSRetry.exponential_backoff()
def list_iam_role_policies_with_backoff(client, role_name):
paginator = client.get_paginator('list_role_policies')
return paginator.paginate(RoleName=role_name).build_full_result()['PolicyNames']
@AWSRetry.exponential_backoff()
def list_iam_attached_role_policies_with_backoff(client, role_name):
paginator = client.get_paginator('list_attached_role_policies')
return paginator.paginate(RoleName=role_name).build_full_result()['AttachedPolicies']
def describe_iam_role(module, client, role):
name = role['RoleName']
try:
role['InlinePolicies'] = list_iam_role_policies_with_backoff(client, name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get inline policies for role %s" % name)
try:
role['ManagedPolicies'] = list_iam_attached_role_policies_with_backoff(client, name)
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't get managed policies for role %s" % name)
return role
def describe_iam_roles(module, client):
name = module.params['name']
path_prefix = module.params['path_prefix']
if name:
try:
roles = [client.get_role(RoleName=name)['Role']]
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == 'NoSuchEntity':
return []
else:
module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name)
except botocore.exceptions.BotoCoreError as e:
module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name)
else:
params = dict()
if path_prefix:
if not path_prefix.startswith('/'):
path_prefix = '/' + path_prefix
if not path_prefix.endswith('/'):
path_prefix = path_prefix + '/'
params['PathPrefix'] = path_prefix
try:
roles = list_iam_roles_with_backoff(client, **params)['Roles']
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Couldn't list IAM roles")
return [camel_dict_to_snake_dict(describe_iam_role(module, client, role)) for role in roles]
def main():
"""
Module action handler
"""
argument_spec = ec2_argument_spec()
argument_spec.update(dict(
name=dict(aliases=['role_name']),
path_prefix=dict(),
))
module = AnsibleAWSModule(argument_spec=argument_spec,
supports_check_mode=True,
mutually_exclusive=[['name', 'path_prefix']])
region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
client = boto3_conn(module, conn_type='client', resource='iam',
region=region, endpoint=ec2_url, **aws_connect_params)
module.exit_json(changed=False, iam_roles=describe_iam_roles(module, client))
if __name__ == '__main__':
main()