Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for multiple assume roles to get collective inventory #1830

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions plugins/doc_fragments/assume_role.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ class ModuleDocFragment:
- The ARN of the IAM role to assume to perform the lookup.
- You should still provide AWS credentials with enough privilege to perform the AssumeRole action.
aliases: ["iam_role_arn"]
assume_role_arns:
description:
- List of ARNs which can be assumed to get collective inventory result.
- This conflicts with `assume_role_arn`.
- You should still provide AWS credentials with enough privilege to perform the AssumeRole action.
aliases: ["iam_role_arns"]
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
version_added: 7.2.0
"""

27 changes: 24 additions & 3 deletions plugins/inventory/aws_ec2.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ def _get_all_hostnames(self, instance, hostnames):

return hostname_list

def _query(self, regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory):
def _query_instances(self, regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory):
"""
:param regions: a list of regions to query
:param include_filters: a list of boto3 filter dictionaries
Expand All @@ -621,6 +621,7 @@ def _query(self, regions, include_filters, exclude_filters, strict_permissions,
"""
instances = []
ids_to_ignore = []

for filter in exclude_filters:
for i in self._get_instances_by_region(
regions,
Expand All @@ -644,7 +645,26 @@ def _query(self, regions, include_filters, exclude_filters, strict_permissions,
for connection, _region in self.all_clients("ssm"):
self._add_ssm_information(connection, instances)

return {"aws_ec2": instances}
return instances

def _query(self, regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory, assume_role_arns):
"""
:param regions: a list of regions to query
:param include_filters: a list of boto3 filter dictionaries
:param exclude_filters: a list of boto3 filter dictionaries
:param strict_permissions: a boolean determining whether to fail or ignore 403 error codes
:param assume_role_arns: list of arns to assume to acquire collective inventory

"""

if assume_role_arns:
instances = []
for role in assume_role_arns:
super().collective_roles(role)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
super().collective_roles(role)
self.collective_roles(role)

instances.extend(self._query_instances(regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory))
return {"aws_ec2": instances}
else:
return {"aws_ec2": self._query_instances(regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory)}

def _add_ssm_information(self, connection, instances):
filters = [{"Key": "AWS:InstanceInformation.InstanceId", "Values": [x["InstanceId"] for x in instances]}]
Expand Down Expand Up @@ -763,6 +783,7 @@ def parse(self, inventory, loader, path, cache=True):
self._sanitize_group_name = self._legacy_script_compatible_group_sanitization

# get user specifications
assume_role_arns = self.get_option("assume_role_arns")
regions = self.get_option("regions")
include_filters = self.build_include_filters()
exclude_filters = self.get_option("exclude_filters")
Expand All @@ -788,7 +809,7 @@ def parse(self, inventory, loader, path, cache=True):
result_was_cached, results = self.get_cached_result(path, cache)

if not result_was_cached:
results = self._query(regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory)
results = self._query(regions, include_filters, exclude_filters, strict_permissions, use_ssm_inventory, assume_role_arns)

self._populate(
results,
Expand Down
19 changes: 18 additions & 1 deletion plugins/plugin_utils/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,13 @@ def _freeze_iam_role(self, iam_role_arn):
def _set_frozen_credentials(self):
options = self.get_options()
iam_role_arn = options.get("assume_role_arn")
if iam_role_arn:
iam_role_arns = options.get("assume_role_arns")
if iam_role_arn and not iam_role_arns:
self._freeze_iam_role(iam_role_arn)
if iam_role_arn and iam_role_arns:
self.fail_aws(
" Conflict here, cannot have not assume_role_arn and assume_role_arns used together "
)

def _describe_regions(self, service):
# Try pulling a list of regions from the service
Expand Down Expand Up @@ -160,6 +165,18 @@ def _boto3_regions(self, service):

return regions

def collective_roles(self, role):
"""
This is used when the user uses `assume_role_arns`, to get inventory from different accounts

:param role: The role mentioned in list of assume roles
"""

# This will be resetting the credential and
# using the base credential to assume different roles
self._frozen_credentials = {}
self._freeze_iam_role(role)

def all_clients(self, service):
"""
Generator that yields a boto3 client and the region
Expand Down
Loading