in reference-artifacts/Custom-Scripts/Update-Scripts/v1.3.8_to_v1.5.0/update.py [0:0]
def impl(accel_prefix, config_file, region, load_db, load_config):
with open(config_file) as f:
config = json.load(f)
with open('prettier-config.json', 'w') as f:
json.dump(config, f, indent=2)
if load_db:
load_to_ddb(accel_prefix, region, config)
if not load_config:
return
print("Converting Configuration file with respect to updated accelerator")
for config_section in config_sections.keys():
if config_section == 'global-options':
print('Updating global options')
global_key_configs = config[config_section]
if config[config_section].get('alz-baseline') == False or config[config_section].get('alz-baseline') == True:
del config[config_section]['alz-baseline']
for key_name in global_key_configs:
## This section will get renamed to aws-org-management
if key_name == 'aws-org-master':
config[config_section][key_name]['add-sns-topics'] = True
if key_name == 'central-security-services':
config[config_section][key_name]['macie-sensitive-sh'] = True
config[config_section][key_name]['fw-mgr-alert-level'] = "Low"
config[config_section][key_name]['security-hub-findings-sns'] = "Low"
config[config_section][key_name]['add-sns-topics'] = True
if key_name == 'cloudwatch':
config[config_section][key_name]['metrics'].append({
'filter-name': 'IgnoreAuthorizationFailureMetric',
'accounts': ["management"],
'regions': ["${HOME_REGION}"],
'loggroup-name': '/${ACCELERATOR_PREFIX_ND}/CloudTrail',
'filter-pattern': '{($.errorCode=\"*UnauthorizedOperation\") || ($.errorCode=\"AccessDenied*\")}',
'metric-namespace': 'CloudTrailMetrics',
'metric-name': 'IgnoreAuthorizationFailureCount',
'metric-value': '1'
})
config[config_section][key_name]['metrics'].append({
'filter-name': 'IgnoreConsoleSignInWithoutMfaMetric',
'accounts': ["management"],
'regions': ["${HOME_REGION}"],
'loggroup-name': '/${ACCELERATOR_PREFIX_ND}/CloudTrail',
'filter-pattern': '{($.eventName=\"ConsoleLogin\") && ($.additionalEventData.MFAUsed !=\"Yes\")}',
'metric-namespace': 'CloudTrailMetrics',
'metric-name': 'IgnoreConsoleSignInWithoutMfaCount',
'metric-value': '1'
})
config[config_section][key_name]['alarms']['default-in-org-mgmt-use-lcl-sns'] = True
config[config_section][key_name]['alarms']['definitions'].append({
'alarm-name': 'IGNORE-AWS-Authorization-Failure',
'metric-name': 'IgnoreAuthorizationFailureCount',
'sns-alert-level': 'Ignore',
'alarm-description': 'Alarms when one or more unauthorized API calls are made (in any account, any region of your AWS Organization).'
})
config[config_section][key_name]['alarms']['definitions'].append({
'alarm-name': 'IGNORE-AWS-Console-SignIn-Without-MFA',
'metric-name': 'IgnoreConsoleSignInWithoutMfaCount',
'sns-alert-level': 'Ignore',
'alarm-description': 'Alarms when MFA is NOT used to sign into the console with IAM (in any account, any region of your AWS Organization).'
})
if key_name == 'aws-config':
rules = config[config_section][key_name]['rules']
for rule in rules:
if rule['name'] == 'EC2-INSTANCE-PROFILE':
rule['runtime'] = 'nodejs14.x'
if rule['name'] == 'EC2-INSTANCE-PROFILE-PERMISSIONS':
rule['runtime'] = 'nodejs14.x'
if key_name == 'scps':
scp_list = config[config_section][key_name]
scp_list.append({
'name': 'Guardrails-Part-0-Core',
'description': 'ASEA Guardrails Part 0 Core Accounts',
'policy': 'ASEA-Guardrails-Part0-CoreOUs.json',
})
for idx, scp in enumerate(scp_list):
if scp['name'] == 'Guardrails-Part-0':
scp['description'] = 'ASEA Guardrails Part 0 Workload Accounts'
scp['policy'] = 'ASEA-Guardrails-Part0-WkldOUs.json'
if scp['name'] == 'Guardrails-Part-2':
del config[config_section][key_name][idx]
if key_name == 'security-hub-frameworks':
standards_list = config[config_section][key_name]['standards']
for standard in standards_list:
if standard['name'] == 'AWS Foundational Security Best Practices v1.0.0':
standard['controls-to-disable'] = ["IAM.1", "EC2.10", "Lambda.4"]
if standard['name'] == 'CIS AWS Foundations Benchmark v1.2.0':
standard['controls-to-disable'] = ["CIS.1.20", "CIS.1.22", "CIS.2.6"]
if config_section == 'mandatory-account-configs':
print('Updating mandatory account configs')
mandatory_key_configs = config[config_section]
for key_name in mandatory_key_configs:
alb_list = config[config_section][key_name].get('alb')
if alb_list:
for alb in alb_list:
if alb.get('tg-stickiness') == "":
del alb['tg-stickiness']
target_list = alb['targets']
for target in target_list:
if target.get('lambda-filename') == "":
del target['lambda-filename']
if config[config_section][key_name].get('share-mad-from') == "":
del config[config_section][key_name]['share-mad-from']
if key_name == 'shared-network':
config[config_section][key_name]['description'] = 'This Account is used for centralized or shared networking resources.'
config[config_section][key_name]['ou'] = 'Infrastructure'
vpc_list = config[config_section][key_name].get('vpc')
if (vpc_list):
for vpc in vpc_list:
if vpc['name'] == 'Endpoint':
vpc['description'] = 'This VPC is used to host AWS Service Endpoints, making AWS services available using private address space.'
if key_name == 'operations':
config[config_section][key_name]['description'] = 'This Account is used for centralized IT Operational resources (MAD, rsyslog, ITSM, etc.).'
if 'mad' in config[config_section][key_name]['deployments']:
config[config_section][key_name]['deployments']['mad']['description'] = 'This directory is a) shared to most accounts in the organization to provide centralized Windows and Linux authentication for cloud workloads, b) used as an identity source for AWS SSO, c) used to inter-connect with on-premises directory services, and d) provides a single identities source for instance and AWS console access.'
config[config_section][key_name]['deployments']['mad']['image-path'] = '/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base'
config[config_section][key_name]['ou'] = 'Infrastructure'
if config[config_section][key_name]['deployments']['mad'].get('share-to-account') == "":
del config[config_section][key_name]['deployments']['mad']['share-to-account']
if key_name == 'perimeter':
config[config_section][key_name]['description'] = 'This Account is used for internet facing ingress/egress security services.'
config[config_section][key_name]['ou'] = 'Infrastructure'
firewall_list = config[config_section][key_name]['deployments'].get('firewalls')
if (firewall_list):
for firewall in firewall_list:
firewall['block-device-mappings'] = ["/dev/sda1", "/dev/sdb"]
if (config[config_section][key_name]['deployments'].get('firewall-manager')):
config[config_section][key_name]['deployments']['firewall-manager']['block-device-mappings'] = ["/dev/sda1", "/dev/sdb"]
vpc_list = config[config_section][key_name].get('vpc')
if (vpc_list):
for vpc in vpc_list:
if vpc['name'] == 'Perimeter':
vpc['description'] = 'This VPC is used to hold centralized ingress/egress (perimeter) security services.'
vpc['alb-forwarding'] = True
if key_name == 'management':
config[config_section][key_name]['description'] = 'This is the Organization Management or root account. Access must be highly restricted. This account should not contain customer resources.'
config[config_section][key_name]['ou'] = 'Security'
vpc_list = config[config_section][key_name].get('vpc')
if (vpc_list):
for vpc in vpc_list:
if vpc['name'] == 'ForSSO':
vpc['description'] = 'This VPC is deployed in the Organization Management/root account to enable the deployment of the Active Directory Connector, enabling the use of Active Directory as the Identity source for AWS SSO.'
if key_name == 'log-archive':
config[config_section][key_name]['ou'] = 'Security'
config[config_section][key_name]['description'] = 'This Account is used to centralized and store immutable logs for the Organization.'
if key_name == 'security':
config[config_section][key_name]['ou'] = 'Security'
config[config_section][key_name]['description'] = 'This Account is used to centralized access to AWS security tooling and consoles.'
if config_section == 'workload-account-configs' and config[config_section] != {}:
print('Updating workload-account-configs')
workload_key_configs = config[config_section]
for key_name in workload_key_configs:
alb_list = config[config_section][key_name].get('alb')
if alb_list:
for alb in alb_list:
if alb.get('tg-stickiness') == "":
del alb['tg-stickiness']
target_list = alb['targets']
for target in target_list:
if target.get('lambda-filename') == "":
del target['lambda-filename']
if config[config_section][key_name].get('share-mad-from') == "":
del config[config_section][key_name]['share-mad-from']
if config_section == 'organizational-units':
print('Updating organizational-units')
organizational_key_configs = config[config_section]
for key_name in organizational_key_configs:
alb_list = config[config_section][key_name].get('alb')
if alb_list:
for alb in alb_list:
if alb.get('tg-stickiness') == "":
del alb['tg-stickiness']
target_list = alb['targets']
for target in target_list:
if target.get('lambda-filename') == "":
del target['lambda-filename']
if config[config_section][key_name].get('share-mad-from') == "":
del config[config_section][key_name]['share-mad-from']
scps = config[config_section][key_name].get('scps')
if 'Guardrails-Part-2' in config[config_section][key_name]['scps']:
if scps:
config[config_section][key_name]['scps'].remove('Guardrails-Part-2')
if key_name == 'core':
print('Updating Core OU')
## The core OU will be renamed to Security and copied to create the Infrastructure OU
config[config_section][key_name]['description'] = 'The Security OU is used to hold AWS accounts containing AWS security resources shared or utilized by the rest of the Organization.'
config[config_section][key_name]['scps'].remove('Guardrails-Part-0')
config[config_section][key_name]['scps'].append('Guardrails-Part-0-Core')
elif key_name == 'Central':
config[config_section][key_name]['description'] = 'The Central OU is used to hold AWS accounts which contain group or team resources used across OU boundaries like code promotion tools.'
vpc_list = config[config_section][key_name]['vpc']
for vpc in vpc_list:
if vpc['name'] == 'Central':
vpc['description'] = 'This VPC is deployed in the shared network account and it\'s subnets are shared out to the Operations account and every account in the Central OU.'
else:
config[config_section][key_name]['description'] = f'The {key_name} OU.'
vpc_list = config[config_section][key_name].get('vpc')
if vpc_list:
for vpc in vpc_list:
vpc['description'] = f'The {vpc["name"]} vpc in the {key_name} OU.'
#create new infrastructure ou as a copy of core
if 'core' in config[config_section]:
infra_ou = config[config_section]['core']
infra_ou['default-budgets']['name'] = 'Default Infrastructure Budget'
infra_ou['description'] = 'The Infrastructure OU'
infra_ou['description'] = 'The infrastructure OU is used to hold AWS accounts containing AWS infrastructure resources shared or utilized by the rest of the Organization.'
config[config_section]['Infrastructure'] = infra_ou
## Update vpc's and subnet's
if (config_section == 'mandatory-account-configs' or
config_section == 'workload-account-configs' or
config_section == 'organizational-units'):
forsso_cidr = "10.24.34.0/24"
perimeter_rfc_cidr = "10.24.34.0/24"
central_rfc_cidr = "10.24.34.0/24"
key_configs = config[config_section]
for key_name in key_configs:
for vindex, vpcConfig in enumerate(key_configs[key_name].get('vpc', [])):
if type(config[config_section][key_name]['vpc'][vindex]['cidr']) == list:
print("Configuration for VPC %s is already in sync with updated SEA" % vpcConfig['name'])
continue
print(f'Updating vpc {config[config_section][key_name]["vpc"][vindex]["name"]}')
## create main pool for cidr block
if (vpcConfig['deploy'] == 'local' and vpcConfig['name'] == 'ForSSO'):
cidr_pool = 'ForSSO'
forsso_cidr = vpcConfig['cidr']
else:
cidr_pool = 'main'
config[config_section][key_name]['vpc'][vindex]['cidr'] = [{
'value': vpcConfig['cidr'],
'size': int(vpcConfig['cidr'].split('/')[-1]),
'pool': cidr_pool,
}]
## create pool for cidr2 block if it exists
if vpcConfig.get('cidr2'):
if type(vpcConfig['cidr2']) == list:
for cidr in vpcConfig['cidr2']:
if (vpcConfig['deploy'] == 'local' and vpcConfig['name'] == 'Perimeter'):
cidr_pool = 'RFC6598b'
perimeter_rfc_cidr = cidr
elif (vpcConfig['deploy'] == 'shared-network' and vpcConfig['name'] == 'Central'):
cidr_pool = 'RFC6598a'
central_rfc_cidr = cidr
else:
cidr_pool = pools['sub']
config[config_section][key_name]['vpc'][vindex]['cidr'].append({
'value': cidr,
'pool': cidr_pool,
'size': int(cidr.split('/')[-1]),
})
else:
if (vpcConfig['deploy'] == 'local' and vpcConfig['name'] == 'Perimeter'):
cidr_pool = 'RFC6598b'
perimeter_rfc_cidr = vpcConfig['cidr2']
elif (vpcConfig['deploy'] == 'shared-network' and vpcConfig['name'] == 'Central'):
cidr_pool = 'RFC6598a'
central_rfc_cidr = vpcConfig['cidr2']
else:
cidr_pool = pools['sub']
config[config_section][key_name]['vpc'][vindex]['cidr'].append({
'value': vpcConfig['cidr2'],
'pool': cidr_pool,
'size': int(vpcConfig['cidr2'].split('/')[-1]),
})
del config[config_section][key_name]['vpc'][vindex]['cidr2']
## add new keys and remove optional keys for vpc
config[config_section][key_name]['vpc'][vindex]['cidr-src'] = 'provided'
if config[config_section][key_name]['vpc'][vindex].get('igw') == False:
del config[config_section][key_name]['vpc'][vindex]['igw']
if not config[config_section][key_name]['vpc'][vindex]['vgw']:
del config[config_section][key_name]['vpc'][vindex]['vgw']
if not config[config_section][key_name]['vpc'][vindex]['pcx']:
del config[config_section][key_name]['vpc'][vindex]['pcx']
if not config[config_section][key_name]['vpc'][vindex]['natgw']:
del config[config_section][key_name]['vpc'][vindex]['natgw']
if 'tgw-attach' in config[config_section][key_name]['vpc'][vindex]:
if not config[config_section][key_name]['vpc'][vindex]['tgw-attach']:
del config[config_section][key_name]['vpc'][vindex]['tgw-attach']
if 'interface-endpoints' in config[config_section][key_name]['vpc'][vindex]:
if not config[config_section][key_name]['vpc'][vindex]['interface-endpoints']:
del config[config_section][key_name]['vpc'][vindex]['interface-endpoints']
## update subnets in vpc
for sindex, subnetConfig in enumerate(vpcConfig['subnets']):
for dindex, subnetDef in enumerate(subnetConfig['definitions']):
current_cidr = subnetDef['cidr'] if subnetDef.get('cidr', None) else subnetDef['cidr2']
print(current_cidr)
print(subnetDef.get('cidr'))
#if config[config_section][key_name]['vpc'][vindex]['subnets'][sindex]['definitions']['route-table'] == 'CentralVPC_Common'
# config[config_section][key_name]['vpc'][vindex]['subnets'][sindex]['definitions']['route-table'] = '${CONFIG::VPC_NAME}VPC_Common'
if (ipaddress.IPv4Network(current_cidr).overlaps(ipaddress.IPv4Network(perimeter_rfc_cidr))):
cidr_pool = 'RFC6598b'
elif (ipaddress.IPv4Network(current_cidr).overlaps(ipaddress.IPv4Network(central_rfc_cidr))):
cidr_pool = 'RFC6598a'
elif (ipaddress.IPv4Network(current_cidr).overlaps(ipaddress.IPv4Network(forsso_cidr))):
cidr_pool = 'ForSSO'
else:
cidr_pool = 'main'
config[config_section][key_name]['vpc'][vindex]['subnets'][sindex]['definitions'][dindex]['cidr'] = {
'value': current_cidr,
'pool': cidr_pool,
'size': int(current_cidr.split('/')[-1]),
}
with open('update-config.json', 'w') as f:
json.dump(config, f, indent=2)
with open('update-config.json') as f:
s = f.read()
with open('update-config.json', 'w') as f:
s = s.replace('"core": {', '"Security": {')
s = s.replace('aws-org-master', 'aws-org-management')
f.write(s)