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.

python · AWS - EC2

Details

IDAwsEC2SyncAccounts
Languagepython
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658
TagsAmazon Web Services

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-list command.
  • 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 Email 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
from unittest.mock import MagicMock

import demistomock as demisto
import pytest
from CommonServerPython import *


def test_internal_request(mocker):
    from AwsEC2SyncAccounts import internal_request

    mock_execute_command = mocker.patch.object(demisto, "executeCommand", return_value=[{"Contents": {"response": "result"}}])

    result = internal_request("POST", "/path/", {"body": "data"})

    assert result == "result"
    mock_execute_command.assert_called_with("core-api-post", {"uri": "/path/", "body": '{"body": "data"}'})


def test_get_account_ids(mocker):
    from AwsEC2SyncAccounts import get_account_ids

    mock_execute_command = mocker.patch.object(demisto, "executeCommand")
    mock_execute_command.return_value = [
        {
            "EntryContext": {
                "AWS.Organizations.Account(val.Id && val.Id == obj.Id)": [
                    {"Id": "1234"},
                    {"Id": "5678"},
                ]
            },
            "HumanReadable": "human_readable",
        }
    ]

    account_ids = get_account_ids("instance_name", 2)

    assert account_ids == (["1234", "5678"], "human_readable")
    mock_execute_command.assert_called_with("aws-org-account-list", {"limit": 2, "using": "instance_name"})


def test_set_instance(mocker):
    import AwsEC2SyncAccounts

    internal_request: MagicMock = mocker.patch.object(AwsEC2SyncAccounts, "internal_request")
    AwsEC2SyncAccounts.set_instance(
        {
            "data": [
                {
                    "name": "accounts_to_access",
                    "hasvalue": False,
                    "value": "",
                },
                {"name": "sessionDuration"},
            ],
        },
        "accounts",
    )
    internal_request.assert_called_with(
        "put",
        "/settings/integration",
        {
            "data": [
                {
                    "name": "accounts_to_access",
                    "hasvalue": True,
                    "value": "accounts",
                },
                {"name": "sessionDuration"},
            ],
        },
    )


def test_update_ec2_instance(mocker):
    import AwsEC2SyncAccounts

    internal_request: MagicMock = mocker.patch.object(
        AwsEC2SyncAccounts,
        "internal_request",
        side_effect=lambda *args: {
            ("post", "/settings/integration/search"): {
                "instances": [
                    {
                        "id": "2fa1071e-af66-4668-8f79-8c57a3e4851d",
                        "name": "AWS - EC2",
                        "configvalues": {
                            "accounts_to_access": "",
                            "sessionDuration": None,
                        },
                        "configtypes": {"accounts_to_access": 0, "sessionDuration": 0},
                        "data": [
                            {
                                "name": "accounts_to_access",
                                "hasvalue": False,
                                "value": "",
                            },
                            {"name": "sessionDuration"},
                        ],
                    },
                    {
                        "name": "wrong name",
                    },
                ]
            },
            ("put", "/settings/integration"): {"configvalues": {"accounts_to_access": "1234,5678"}},
        }.get(args[:2]),
    )

    result = AwsEC2SyncAccounts.update_ec2_instance(["1234", "5678"], "AWS - EC2")

    assert internal_request.mock_calls[0].args == ("post", "/settings/integration/search")
    assert internal_request.mock_calls[1].args == (
        "put",
        "/settings/integration",
        {
            "id": "2fa1071e-af66-4668-8f79-8c57a3e4851d",
            "name": "AWS - EC2",
            "configvalues": {
                "accounts_to_access": "",
                "sessionDuration": None,
            },
            "configtypes": {"accounts_to_access": 0, "sessionDuration": 0},
            "data": [
                {
                    "name": "accounts_to_access",
                    "hasvalue": True,
                    "value": "1234,5678",
                },
                {"name": "sessionDuration"},
            ],
        },
    )
    assert result == "Successfully updated ***AWS - EC2*** with accounts:"


def test_remove_excluded_accounts():
    from AwsEC2SyncAccounts import remove_excluded_accounts

    accounts = ["1", "2", "3", "4", "5"]

    accounts = remove_excluded_accounts(accounts, "1,2,3")

    assert set(accounts) == {"4", "5"}


def test_errors():
    import AwsEC2SyncAccounts as sync

    with pytest.raises(DemistoException, match="Unexpected error while configuring AWS - EC2 instance with accounts"):
        sync.get_instance = lambda _: 1 / 0
        sync.update_ec2_instance([], "")

    with pytest.raises(DemistoException, match="Unexpected output from 'aws-org-account-list':\nNone"):
        sync.demisto.executeCommand = lambda *_: {}["key"]
        sync.get_account_ids("", 0)