AwsEC2SyncAccounts
Update an AWS - EC2 instance with a list of accounts in an AWS organization, which will allow EC2 commands to run in all of them.
- Type
- python
- Pack
- AWS-EC2
Source
import demistomock as demisto
from CommonServerPython import *
ACCOUNT_LIST_COMMAND = "aws-org-account-list"
EC2_ACCOUNTS_PARAM = "accounts_to_access"
def internal_request(method: str, uri: str, body: dict = {}) -> dict:
"""A wrapper for demisto.internalHttpRequest.
Args:
method (str): HTTP method such as: GET or POST
uri (str): Server uri to request. For example: "/contentpacks/marketplace/HelloWorld".
body (dict, optional): Optional body for a POST request. Defaults to {}.
Returns:
dict: The body of request response.
"""
return demisto.executeCommand(f"core-api-{method.lower()}", {"uri": uri, "body": json.dumps(body)})[0]["Contents"]["response"] # type: ignore
def get_account_ids(ec2_instance_name: str | None, limit: int | None) -> tuple[list[str], str]:
"""Get the AWS organization accounts using the `aws-org-account-list` command.
Returns:
list[str]: A list of AWS account IDs.
"""
try:
command_args = assign_params(limit=limit, using=ec2_instance_name)
account_list_result: list[dict] = demisto.executeCommand(ACCOUNT_LIST_COMMAND, command_args) # type: ignore
accounts = dict_safe_get(
account_list_result, (0, "EntryContext", "AWS.Organizations.Account(val.Id && val.Id == obj.Id)"), []
)
return [account["Id"] for account in accounts], str(dict_safe_get(account_list_result, (0, "HumanReadable"), ""))
except ValueError as e:
raise DemistoException(f"The command {ACCOUNT_LIST_COMMAND!r} must be operational to run this script.\nServer error: {e}")
except StopIteration:
raise DemistoException(f"AWS - Organizations instance {ec2_instance_name!r} was not found.")
except (KeyError, TypeError):
account_list_result = locals().get("account_list_result") # type: ignore # catch unbound variable error
raise DemistoException(f"Unexpected output from {ACCOUNT_LIST_COMMAND!r}:\n{account_list_result}")
except Exception as e:
raise DemistoException(f"Unexpected error while fetching accounts:\n{e}")
def get_instance(ec2_instance_name: str) -> dict:
"""Get the object of the instance with the name provided.
Args:
instance_name (str): The name of the instance to get.
Returns:
dict: The instance object.
"""
integrations = internal_request("post", "/settings/integration/search")
return next(inst for inst in integrations["instances"] if inst["name"] == ec2_instance_name)
def set_instance(instance: dict, accounts: str) -> dict:
"""Set an instance configuration with the accounts.
Args:
instance (dict): The instance object to configure.
accounts (str): The accounts to add to the body.
Returns:
dict: The server response from the configuration call.
"""
accounts_param: dict = next(param for param in instance["data"] if param["name"] == EC2_ACCOUNTS_PARAM)
accounts_param.update({"hasvalue": True, "value": accounts})
return internal_request("put", "/settings/integration", instance)
def remove_excluded_accounts(account_ids: list, accounts_to_exclude: str | None) -> list[str]:
return list(set(account_ids) - set(argToList(accounts_to_exclude))) if accounts_to_exclude else account_ids
def update_ec2_instance(account_ids: list[str], ec2_instance_name: str) -> str:
"""Update an AWS - EC2 instance with AWS Organization accounts.
Args:
account_ids (list[str]): The accounts to configure the instance with.
instance_name (str): The name of the instance to configure.
Returns:
str: A message regarding the outcome of the script run.
"""
accounts_as_str = ",".join(account_ids)
try:
instance = get_instance(ec2_instance_name)
if instance["configvalues"][EC2_ACCOUNTS_PARAM] == accounts_as_str:
return f"Account list in ***{ec2_instance_name}*** is up to date."
response = set_instance(instance, accounts_as_str)
if response["configvalues"][EC2_ACCOUNTS_PARAM] != accounts_as_str:
demisto.debug(f"{response=}")
raise DemistoException(f"Attempt to update {ec2_instance_name!r} with accounts {accounts_as_str} has failed.")
return f"Successfully updated ***{ec2_instance_name}*** with accounts:"
except StopIteration:
raise DemistoException(f"AWS - EC2 instance {ec2_instance_name!r} was not found or is not an AWS - EC2 instance.")
except (TypeError, KeyError) as e:
raise DemistoException(f'Please make sure a "Core REST API" instance is enabled.\nError: {e}')
except Exception as e:
raise DemistoException(f"Unexpected error while configuring AWS - EC2 instance with accounts {accounts_as_str!r}:\n{e}")
def main():
try:
args: dict = demisto.args()
account_ids, readable_output = get_account_ids(args.get("org_instance_name"), arg_to_number(args.get("max_accounts")))
account_ids = remove_excluded_accounts(account_ids, args.get("exclude_accounts"))
result = update_ec2_instance(account_ids, args["ec2_instance_name"])
return_results(CommandResults(readable_output=f"## {result} \n--- \n{readable_output}"))
except Exception as e:
return_error(f"Error in AwsEC2SyncAccounts: {e}")
if __name__ in ("__main__", "builtins", "__builtin__"):
main()
README
Update an AWS - EC2 instance with a list of accounts in an AWS organization, which will allow EC2 commands to run in all of them.
This script can be run on a schedule to keep an AWS - EC2 instance in sync with the created, deleted or removed accounts of the organization.
Prerequisites
- An AWS - EC2 instance.
- An AWS - Organizations instance with a working
aws-org-account-listcommand. - A Core REST API instance.
Script Data
| Name | Description |
|---|---|
| Script Type | python3 |
| Tags | Amazon Web Services |
| Cortex XSOAR Version | 6.10.0 |
Inputs
| Argument Name | Description |
|---|---|
| ec2_instance_name | The name of the AWS - EC2 instance integration to update. |
| org_instance_name | The name of the AWS - Organizations instance to collect account from. If not provided, the primary instance will be used. |
| exclude_accounts | A comma-separated list of accounts to exclude. |
| max_accounts | The maximum number of accounts to retrieve. Default is 50. |
Outputs
There are no outputs for this script.
Script Examples
Example command
!AwsEC2SyncAccounts ec2_instance_name="AWS_EC2_Instance" org_instance_name="AWS_Organizations_Instance"
Human Readable Output
Successfully updated AWS_EC2_Instance with accounts
AWS Organization Accounts
Id Arn Name JoinedMethod JoinedTimestamp Status 111222333444 arn:aws:organizations::111222333444:account/o-abcde12345/111222333444 Name user@xsoar.com CREATED 2023-09-04 09:17:14.299000+00:00 ACTIVE 111222333444 arn:aws:organizations::111222333444:account/o-abcde12345/111222333444 John Doe user@xsoar.com INVITED 2022-07-25 09:11:23.528000+00:00 SUSPENDED