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

Feat/nested ou targets #538

Merged
merged 18 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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
10 changes: 8 additions & 2 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,16 @@ targets:
# stages, each stage containing up to X accounts
size: 30
exclude:
# (Optional) List of accounts to exclude from this target.
# Currently only supports account Ids
# (Optional) List of accounts to exclude from this path.
- 9999999999
properties: ...
- path: /my_ou/production/**/* # This would target all accounts in the OU path
regions: [eu-central-1, us-west-1]
name: production_step
exclude: # (Optional) List of OU Paths and Account Ids
- /my-ou/production/alpha # excludes any accounts and OUs in this path.
- 11111111111 # Excludes this account, regardless of OU path.
properties: ...
```

CodePipeline has a limit of 50 actions per stage.
Expand Down
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ isort==5.12.0
mock==5.1.0
pylint==2.17.4
pytest~=7.4.0
pytest-cov==3.0.0
tox==3.28.0
yamllint==1.32.0
23 changes: 15 additions & 8 deletions src/lambda_codebase/account_processing/configure_account_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,44 @@
Will not delete tags that aren't
in the config file.
"""

from organizations import Organizations

import boto3
from aws_xray_sdk.core import patch_all
from logger import configure_logger

patch_all()
LOGGER = configure_logger(__name__)
ORG_CLIENT = boto3.client("organizations")


def create_account_tags(account_id, tags, org_session: Organizations):
def create_account_tags(account_id, tags, client):
LOGGER.info(
"Ensuring Account: %s has tags: %s",
account_id,
tags,
)
org_session.create_account_tags(account_id, tags)
formatted_tags = [
{"Key": str(key), "Value": str(value)}
for tag in tags
for key, value in tag.items()
]
LOGGER.debug(
"Ensuring Account: %s has tags (formatted): %s",
account_id,
formatted_tags,
)
client.tag_resource(ResourceId=account_id, Tags=formatted_tags)


def lambda_handler(event, _):
if event.get("tags"):
organizations = Organizations(boto3)
create_account_tags(
event.get("account_id"),
event.get("tags"),
organizations,
ORG_CLIENT,
)
else:
LOGGER.info(
"Account: %s does not need tags configured",
event.get('account_full_name'),
event.get("account_full_name"),
)
return event
36 changes: 19 additions & 17 deletions src/lambda_codebase/account_processing/get_account_regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,33 @@
AWS_PARTITION = os.getenv("AWS_PARTITION")


def get_default_regions_for_account(ec2_client):
filtered_regions = ec2_client.describe_regions(
AllRegions=False,
Filters=[
{
"Name": "opt-in-status",
"Values": [
"opt-in-not-required",
"opted-in",
],
},
],
)["Regions"]
default_regions = [region["RegionName"] for region in filtered_regions]
return default_regions


def lambda_handler(event, _):
LOGGER.info("Fetching Default regions %s", event.get('account_full_name'))
LOGGER.info("Fetching Default regions %s", event.get("account_full_name"))
sts = STS()
account_id = event.get("account_id")
role = sts.assume_cross_account_role(
f"arn:{AWS_PARTITION}:iam::{account_id}:role/{ADF_ROLE_NAME}",
"adf_account_get_regions",
)
default_regions = get_default_regions_for_account(role.client("ec2"))

ec2_client = role.client("ec2")
default_regions = [
region["RegionName"]
for region in ec2_client.describe_regions(
AllRegions=False,
Filters=[
{
"Name": "opt-in-status",
"Values": [
"opt-in-not-required",
"opted-in"
],
}
],
)["Regions"]
]
LOGGER.debug("Default regions for %s: %s", account_id, default_regions)
return {
**event,
Expand Down
5 changes: 5 additions & 0 deletions src/lambda_codebase/account_processing/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
[pytest]
testpaths = tests
addopts = --cov=./src/lambda_codebase/account_processing/ --cov-fail-under=50 --cov-report term

[coverage:run]
omit = tests/

62 changes: 62 additions & 0 deletions src/lambda_codebase/account_processing/tests/test_account_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Tests the account tag configuration lambda
"""

import unittest
import boto3
from botocore.stub import Stubber
from aws_xray_sdk import global_sdk_config
from ..configure_account_tags import (
create_account_tags,
)

global_sdk_config.set_sdk_enabled(False)

# pylint: disable=W0106,R0201
class SuccessTestCase(unittest.TestCase):
def test_account_tag_creation(self):
test_event = {"account_id": "123456789012", "tags": [{"CreatedBy": "ADF"}]}
ou_client = boto3.client("organizations")
stubber = Stubber(ou_client)
stubber.add_response(
"tag_resource",
{},
{
"Tags": [{"Key": "CreatedBy", "Value": "ADF"}],
"ResourceId": "123456789012",
},
),
stubber.activate()
create_account_tags(
test_event.get("account_id"), test_event.get("tags"), ou_client
)
StewartW marked this conversation as resolved.
Show resolved Hide resolved
stubber.assert_no_pending_responses()

def test_account_tag_creation_multiple_tags(self):
test_event = {
"account_id": "123456789012",
"tags": [
{
"CreatedBy": "ADF",
"TagName": "TagValue",
}
],
}
ou_client = boto3.client("organizations")
stubber = Stubber(ou_client)
stubber.add_response(
"tag_resource",
{},
{
"Tags": [
{"Key": "CreatedBy", "Value": "ADF"},
{"Key": "TagName", "Value": "TagValue"},
],
"ResourceId": "123456789012",
},
),
stubber.activate()
create_account_tags(
test_event.get("account_id"), test_event.get("tags"), ou_client
)
stubber.assert_no_pending_responses()
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""
Tests the account tag configuration lambda
"""

import unittest
import boto3
from botocore.stub import Stubber
from aws_xray_sdk import global_sdk_config
from ..get_account_regions import (
get_default_regions_for_account,
)

global_sdk_config.set_sdk_enabled(False)

# pylint: disable=W0106
class SuccessTestCase(unittest.TestCase):
@staticmethod
def test_get_default_regions_for_account():
ec2_client = boto3.client("ec2")
stubber = Stubber(ec2_client)
stubber.add_response(
"describe_regions",
{
"Regions": [
{
"Endpoint": "blah",
"RegionName": "us-east-1",
"OptInStatus": "opt-in-not-required",
},
{
"Endpoint": "blah",
"RegionName": "us-east-2",
"OptInStatus": "opt-in-not-required",
},
{
"Endpoint": "blah",
"RegionName": "us-east-3",
"OptInStatus": "opted-in",
},
{
"Endpoint": "blah",
"RegionName": "us-east-4",
"OptInStatus": "opted-in",
},
]
},
{
"AllRegions": False,
"Filters": [
{
"Values": [
"opt-in-not-required",
"opted-in",
],
"Name": "opt-in-status",
},
],
},
),
stubber.activate()
regions = get_default_regions_for_account(ec2_client)
assert regions == ["us-east-1", "us-east-2", "us-east-3", "us-east-4"]
Loading
Loading