mirror of https://github.com/ansible/ansible.git
[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 presentpull/33830/head
parent
1bb974a917
commit
c27ded6bbc
@ -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()
|
Loading…
Reference in New Issue