AWSAccountHierarchy
Determine AWS account hierarchy by looking up parent objects until the organization level is reached.
- Type
- python
- Pack
- AWS-Enrichment-Remediation
Source
import demistomock as demisto # noqa: F401
from CommonServerPython import * # noqa: F401
from typing import Any
import traceback
""" STANDALONE FUNCTION """
def lookup(parent_obj: str, level: int, instance_to_use: str) -> tuple[str, dict]:
"""
Lookup information on a organization unit (ou) or root object. Unless the current lookup
is a root object, it returns parent object to lookup and results of current lookup.
Args:
parent_obj (str): root/ou object in number format.
level (int): the current level that the object is (ascending).
instance_to_use (str): what integration instance to use.
Returns:
str: parent object to look up next or "NONE" for error handling and "stop" if no parent.
dict: dictionary of id, name and level of the lookup object.
"""
temp: dict[str, str] = {}
try:
if "ou-" in parent_obj:
ou_info = execute_command(
"aws-org-organization-unit-get",
{"organization_unit_id": parent_obj, "using": instance_to_use},
)
if not ou_info:
return "NONE", temp
temp["level"] = str(level)
temp["id"] = ou_info.get("Id", "")
temp["name"] = ou_info.get("Name", "")
temp["arn"] = ou_info.get("Arn", "")
ou_parent = execute_command(
"aws-org-parent-list",
{"child_id": parent_obj, "using": instance_to_use},
)
if not ou_parent:
return "NONE", temp
next_one = ou_parent[0].get("Id", "")
elif "r-" in parent_obj:
next_one = "stop"
root_info = execute_command("aws-org-root-list", {"using": instance_to_use})
if not root_info:
return "NONE", temp
root = root_info.get("AWS.Organizations.Root(val.Id && val.Id == obj.Id)")[0]
temp["level"] = str(level)
temp["id"] = root.get("Id", "")
temp["name"] = root.get("Name", "")
temp["arn"] = root.get("Arn", "")
else:
raise ValueError("unexpected object type")
except TypeError:
return "NONE", temp
else:
return next_one, temp
""" COMMAND FUNCTION """
def aws_account_heirarchy(args: dict[str, Any]) -> CommandResults:
"""
Determine AWS account hierarchy by looking up parent objects until the root level is reached.
Args:
args (dict): Command arguments from XSOAR.
Returns:
list[CommandResults]: outputs, readable outputs and raw response for XSOAR.
"""
account_id = args.get("account_id")
if not account_id:
raise ValueError("account_id not specified")
# Using `demisto.executeCommand` instead of `execute_command` because for
# multiple integration instances we can expect one too error out.
account_info = demisto.executeCommand("aws-org-account-list", {"account_id": account_id})
account_returned = [account for account in account_info if (not isError(account) and account.get("Contents").get("Arn"))]
if not account_returned:
return CommandResults(readable_output="could not find specified account info")
else:
match_account = account_returned[0].get("Contents")
instance_to_use = account_returned[0]["Metadata"]["instance"]
level = 1
hierarchy = [
{
"level": "account",
"id": match_account.get("Id", ""),
"name": match_account.get("Name", ""),
"arn": match_account.get("Arn", ""),
}
]
account_parent = demisto.executeCommand("aws-org-parent-list", {"child_id": account_id, "using": instance_to_use})
if isError(account_parent):
return CommandResults(readable_output="could not find specified account parent")
next_one, to_append = lookup(account_parent[0].get("Contents", {})[0].get("Id", ""), level, instance_to_use)
if next_one == "NONE":
return CommandResults(readable_output="could not find specified ou/root info")
hierarchy.append(to_append)
try:
while "stop" not in next_one:
level += 1
next_one, to_append = lookup(next_one, level, instance_to_use)
if next_one == "NONE" or next_one is None:
return CommandResults(readable_output="could not find specified ou/root info")
hierarchy.append(to_append)
except TypeError:
return CommandResults(readable_output="could not find specified ou/root info")
return CommandResults(
outputs_prefix="AWSHierarchy",
outputs_key_field="level",
outputs=hierarchy,
)
""" MAIN FUNCTION """
def main():
try:
return_results(aws_account_heirarchy(demisto.args()))
except Exception as ex:
demisto.error(traceback.format_exc()) # print the traceback
return_error(f"Failed to execute AWSAccountHierarchy. Error: {str(ex)}")
""" ENTRY POINT """
if __name__ in ("__main__", "__builtin__", "builtins"):
main()
README
Determine AWS account hierarchy by looking up parent objects until the organization level is reached.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Cortex XSOAR Version | 6.10.0 |
Dependencies
This script uses the following commands and scripts.
- aws-org-parent-list
- aws-org-organization-unit-get
- aws-org-root-list
- aws-org-account-list
Inputs
| Argument Name | Description |
|---|---|
| account_id | The unique identifier (ID) of the Amazon Web Services account that you want information about. |
Outputs
| Path | Description | Type |
|---|---|---|
| AWSHierarchy.id | ID of the account/OU/root object such as `111111111111`. | string |
| AWSHierarchy.level | Level in relation to the original AWS account such as account, 1, 2, etc. | string |
| AWSHierarchy.arn | ARN of the account/OU/root object such as `arn:aws:organizations::111111111111:root/o-2222222222/r-3333`. | string |
| AWSHierarchy.name | Human readable name of the account/OU/root object such as `aws-account-n`. | Unknown |