From d2798a695c09609fbd51c7c62a61884d9859528d Mon Sep 17 00:00:00 2001 From: Brian Crissup Date: Thu, 3 Jul 2025 14:53:43 -0400 Subject: [PATCH 1/3] fix(asea): initial duplicate vpc names implementation (#1286) --- .../lza-upgrade/src/asea-config/index.ts | 18 +++++- .../lza-upgrade/src/convert-config.ts | 62 ++++++++++--------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts b/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts index 51e13cfba..406d0562d 100644 --- a/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts +++ b/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts @@ -11,6 +11,7 @@ * and limitations under the License. */ import * as t from './types'; +import * as crypto from 'crypto'; export const MandatoryAccountType = t.enums('MandatoryAccountType', [ 'master', @@ -1323,10 +1324,12 @@ export class AcceleratorConfig { // Add mandatory account VPC configuration first for (const [accountKey, accountConfig] of this.getMandatoryAccountConfigs()) { for (const vpcConfig of accountConfig.vpc || []) { + const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); vpcConfigs.push({ accountKey, vpcConfig, ouKey: accountConfig.ou, + lzaVpcName }); } } @@ -1346,13 +1349,14 @@ export class AcceleratorConfig { continue; } } - vpcConfig.lzaVpcName = `${vpcConfig.name}_${accountKey}`; + vpcConfig.lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); if (vpcConfig['cidr-src'] === 'dynamic') { + const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); vpcConfigs.push({ ouKey, accountKey, vpcConfig, - lzaVpcName: `${vpcConfig.name}_${accountKey}`, + lzaVpcName, }); } } @@ -1361,6 +1365,7 @@ export class AcceleratorConfig { ouKey, vpcConfig, excludeAccounts, + lzaVpcName: createLzaVpcName(vpcConfig.name, ouKey, vpcConfig.region), }); } } else { @@ -1369,6 +1374,7 @@ export class AcceleratorConfig { ouKey, accountKey: destinationAccountKey, vpcConfig, + lzaVpcName: createLzaVpcName(vpcConfig.name, destinationAccountKey, vpcConfig.region) }); } } @@ -1381,6 +1387,7 @@ export class AcceleratorConfig { accountKey, vpcConfig, ouKey: accountConfig.ou, + lzaVpcName: createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region), }); } } @@ -1406,3 +1413,10 @@ export class AcceleratorConfig { })); } } + +export function createLzaVpcName(vpcName: string, accountKey: string, region: string): string { + const md5Hash = crypto.createHash('md5').update(`${vpcName}_${accountKey}_${region}`).digest('hex'); + const vpcNameWithType = vpcName.endsWith('_vpc') ? vpcName : `${vpcName}_vpc`; + const lzaVpcName = `${vpcNameWithType}..${md5Hash.substring(0,5)}`; + return lzaVpcName; +} \ No newline at end of file diff --git a/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts b/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts index 39523f5ec..af921c3e8 100644 --- a/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts +++ b/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts @@ -35,6 +35,7 @@ import { TransitGatewayRouteConfig, VpcConfig, VpcFlowLogsDestinationConfig, + createLzaVpcName, } from './asea-config'; import { loadAseaConfig } from './asea-config/load'; import * as WriteToSourcesTypes from './common//utils/types/writeToSourcesTypes'; @@ -539,9 +540,9 @@ export class ConvertAseaConfig { name: createNetworkFirewallName(firewallConfigName, this.aseaPrefix), subnetChangeProtection: false, tags: [], - vpc: createVpcName(lzaVpcName ?? vpcConfig.name), + vpc: lzaVpcName!, subnets: this.getAzSubnets(vpcConfig, networkFirewallConfig.subnet.name).map((subnet) => - createSubnetName(lzaVpcName ?? vpcConfig.name, subnet.subnetName, subnet.az), + createSubnetName(vpcConfig.name, subnet.subnetName, subnet.az), ), }); } @@ -1776,7 +1777,7 @@ export class ConvertAseaConfig { name: instanceNameWithAz, account, launchTemplate, - vpc: `${vpcName}_vpc`, + vpc: firewallScopedVpcConfig?.lzaVpcName!, terminationProtection, detailedMonitoring, tags, @@ -2432,7 +2433,7 @@ export class ConvertAseaConfig { const setConfigRulesConfig = async () => { if (!globalOptions['aws-config']) return; // TODO: Consider account regions for deploymentTargets - const currentNodeRuntime = 'nodejs18.x'; + const currentNodeRuntime = 'nodejs20.x'; const rulesWithTarget: (AwsConfigRule & { deployTo?: string[]; excludedAccounts?: string[]; @@ -2800,7 +2801,7 @@ export class ConvertAseaConfig { if (route['target-vpc']) { return { account: this.getAccountKeyforLza(globalOptions, route['target-account'] || accountKey), - vpcName: createVpcName(route['target-vpc']), + vpcName: this.getLzaVpcName(route['target-vpc']), }; } else if (route['target-vpn']) { return { @@ -2967,12 +2968,12 @@ export class ConvertAseaConfig { sources: [], }; for (const source of rule.source) { - let sourceVpcAccountKey: string | undefined = undefined; + let sourceVpcConfig: ResolvedVpcConfig | undefined; if (SubnetSourceConfig.is(source)) { - sourceVpcAccountKey = this.vpcConfigs.find(({ vpcConfig }) => vpcConfig.name === source.vpc)?.accountKey; + sourceVpcConfig = this.vpcConfigs.find(({ vpcConfig }) => vpcConfig.name === source.vpc); } if (SecurityGroupSourceConfig.is(source)) { - lzaRule.sources.push({ + lzaRule.sources.push({ securityGroups: source['security-group'].map(securityGroupName), }); } else if (SubnetSourceConfig.is(source)) { @@ -2980,14 +2981,14 @@ export class ConvertAseaConfig { //account: this.getAccountKeyforLza(globalOptions, source.account || accountKey || ''), account: this.getAccountKeyforLza( globalOptions, - sourceVpcAccountKey || source.account || accountKey || '', + sourceVpcConfig?.accountKey || source.account || accountKey || '', ), subnets: source.subnet.flatMap((sourceSubnet) => aseaConfig - .getAzSubnets(sourceVpcAccountKey || source.account || accountKey || '', source.vpc, sourceSubnet) + .getAzSubnets(sourceVpcConfig?.accountKey || source.account || accountKey || '', source.vpc, sourceSubnet) .map((s) => createSubnetName(source.vpc, s.subnetName, s.az)), ), - vpc: createVpcName(source.vpc), + vpc: sourceVpcConfig?.lzaVpcName ?? source.vpc, }); } else { lzaRule.sources.push(source); @@ -3011,7 +3012,6 @@ export class ConvertAseaConfig { rules: NaclConfig[], vpcConfig: VpcConfig, accountKey?: string, - lzaVpcName?: string, ) => { const lzaRules: (ConvertConfigTypes.LzaNaclInboundRuleType | ConvertConfigTypes.LzaNaclOutboundRuleType)[] = []; for (const rule of rules) { @@ -3055,18 +3055,17 @@ export class ConvertAseaConfig { }); } else { // determine which vpc the nacl rule references - // use the lzaVpcName when the config is from ou let destination: string; if (dest.vpc === vpcConfig.name) { - destination = createVpcName(lzaVpcName ?? vpcConfig.name); + destination = vpcConfig.name; } else { - destination = createVpcName(dest.vpc); + destination = dest.vpc; } + const destinationAccountKey = destinationVpcKey ? this.getAccountKeyforLza(globalOptions, destinationVpcKey): undefined; target = { - account: destinationVpcKey ? this.getAccountKeyforLza(globalOptions, destinationVpcKey) : undefined, + account: destinationAccountKey, subnet: createSubnetName(dest.vpc, ruleSubnet.subnetName, ruleSubnet.az), - //vpc: createVpcName(dest.vpc), - vpc: destination, + vpc: createLzaVpcName(destination, destinationAccountKey!, vpcConfig.region), region: targetRegion, }; } @@ -3086,7 +3085,7 @@ export class ConvertAseaConfig { } return lzaRules; }; - const prepareNaclConfig = (vpcConfig: VpcConfig, accountKey?: string, lzaVpcName?: string) => { + const prepareNaclConfig = (vpcConfig: VpcConfig, accountKey?: string) => { const naclSubnetConfigs = vpcConfig.subnets?.filter((s) => !!s.nacls); if (!naclSubnetConfigs) return; const nacls = []; @@ -3100,8 +3099,8 @@ export class ConvertAseaConfig { subnetAssociations: this.getAzSubnets(vpcConfig, subnetConfig.name).map((s) => createSubnetName(vpcConfig.name, s.subnetName, s.az), ), - inboundRules: prepareNaclRules(inboundRules, vpcConfig, accountKey, lzaVpcName), - outboundRules: prepareNaclRules(outboundRules, vpcConfig, accountKey, lzaVpcName), + inboundRules: prepareNaclRules(inboundRules, vpcConfig, accountKey), + outboundRules: prepareNaclRules(outboundRules, vpcConfig, accountKey), }); } return nacls; @@ -3205,6 +3204,7 @@ export class ConvertAseaConfig { vpcConfig: VpcConfig, lzaEndpointsConfig: ConvertConfigTypes.ResolverEndpointsType[], lzaEndpointsRulesConfig: ConvertConfigTypes.ResolverEndpointRulesType[], + accountKey: string | undefined, ): ConvertConfigTypes.ResolverEndpointsType[] => { let inboundResolver = vpcConfig.resolvers!.inbound; let outboundResolver = vpcConfig.resolvers!.outbound; @@ -3212,7 +3212,7 @@ export class ConvertAseaConfig { if (inboundResolver) { lzaEndpointsConfig.push({ name: `${vpcConfig.name}InboundEndpoint`, - vpc: createVpcName(vpcConfig.lzaVpcName ?? vpcConfig.name), + vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region), subnets: vpcConfig.subnets ?.find((subnetItem) => subnetItem.name === vpcConfig.resolvers?.subnet) @@ -3226,7 +3226,7 @@ export class ConvertAseaConfig { if (outboundResolver) { lzaEndpointsConfig.push({ name: `${vpcConfig.name}OutboundEndpoint`, - vpc: createVpcName(vpcConfig.lzaVpcName ?? vpcConfig.name), + vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region), subnets: vpcConfig.subnets ?.find((subnetItem) => subnetItem.name === vpcConfig.resolvers?.subnet) @@ -3262,7 +3262,7 @@ export class ConvertAseaConfig { return lzaEndpointsRulesConfig; }; - const prepareResolverConfig = (vpcConfig: VpcConfig) => { + const prepareResolverConfig = (vpcConfig: VpcConfig, accountKey: string | undefined) => { let lzaResolverConfig: { endpoints: ConvertConfigTypes.ResolverEndpointsType[] | undefined; queryLogs: { name: string; destinations: string[] } | undefined; @@ -3274,7 +3274,7 @@ export class ConvertAseaConfig { let endpoints: any[] = []; if (vpcConfig.resolvers) { rules = prepareRulesConfig(vpcConfig, lzaEndpointsRulesConfig); - endpoints = prepareEndpointsConfig(vpcConfig, lzaEndpointsConfig, rules!); + endpoints = prepareEndpointsConfig(vpcConfig, lzaEndpointsConfig, rules!, accountKey); } lzaResolverConfig = { @@ -3419,7 +3419,7 @@ export class ConvertAseaConfig { const prepareVpcConfig = ({ accountKey, ouKey, vpcConfig, excludeAccounts, lzaVpcName }: ResolvedVpcConfig) => { return { - name: createVpcName(lzaVpcName ?? vpcConfig.name), + name: lzaVpcName ?? createVpcName(vpcConfig.name), account: accountKey ? this.getAccountKeyforLza(globalOptions, accountKey) : undefined, deploymentTargets: !accountKey ? { @@ -3458,13 +3458,13 @@ export class ConvertAseaConfig { useCentralEndpoints: vpcConfig['use-central-endpoints'], natGateways: prepareNatGatewayConfig(vpcConfig), securityGroups: prepareSecurityGroupsConfig(vpcConfig, accountKey), - networkAcls: prepareNaclConfig(vpcConfig, accountKey, lzaVpcName), + networkAcls: prepareNaclConfig(vpcConfig, accountKey), vpcFlowLogs: prepareVpcFlowLogs(vpcConfig['flow-logs']), subnets: prepareSubnetConfig(vpcConfig, ouKey, accountKey), transitGatewayAttachments: prepareTgwAttachConfig(vpcConfig), virtualPrivateGateway: vpcConfig.vgw, routeTables: prepareRouteTableConfig(vpcConfig, accountKey), - vpcRoute53Resolver: prepareResolverConfig(vpcConfig), + vpcRoute53Resolver: prepareResolverConfig(vpcConfig, accountKey), }; }; @@ -3493,7 +3493,7 @@ export class ConvertAseaConfig { .filter(({ vpcConfig }) => !!vpcConfig.pcx) .map(({ vpcConfig }) => ({ name: peeringConnectionName(vpcConfig.name, vpcConfig.pcx!['source-vpc']), - vpcs: [createVpcName(vpcConfig.lzaVpcName ?? vpcConfig.name), createVpcName(vpcConfig.pcx!['source-vpc'])], + vpcs: [this.getLzaVpcName(vpcConfig.name), this.getLzaVpcName(vpcConfig.pcx!['source-vpc'])], })); }; await setCertificatesConfig(); @@ -3660,6 +3660,10 @@ export class ConvertAseaConfig { ); } + private getLzaVpcName(vpcName: string): string { + return this.vpcConfigs.find((vc) => vc.vpcConfig.name === vpcName )?.lzaVpcName! + } + private getVpcCidr({ accountKey, vpcConfig, ouKey }: { accountKey?: string; vpcConfig: VpcConfig; ouKey?: string }) { const cidrs: string[] = []; if (vpcConfig['cidr-src'] === 'provided') { From 2dd42eea8c48c2ce6addf776b44cc9d70781cd5f Mon Sep 17 00:00:00 2001 From: Olivier Gaumond Date: Fri, 29 Aug 2025 10:41:50 -0400 Subject: [PATCH 2/3] fix(asea): add option to append unique suffixes to vpc names --- .../lza-upgrade/src/asea-config/index.ts | 24 +++++++++---------- .../Custom-Scripts/lza-upgrade/src/config.ts | 1 + .../lza-upgrade/src/convert-config.ts | 16 +++++++------ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts b/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts index 406d0562d..21cc68bfe 100644 --- a/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts +++ b/reference-artifacts/Custom-Scripts/lza-upgrade/src/asea-config/index.ts @@ -1318,18 +1318,18 @@ export class AcceleratorConfig { * Find all VPC configurations in mandatory accounts, workload accounts and organizational units. VPC configuration in * organizational units will have the correct `accountKey` based on the `deploy` value of the VPC configuration. */ - getVpcConfigs(): ResolvedVpcConfig[] { + getVpcConfigs(appendSuffix: boolean): ResolvedVpcConfig[] { const vpcConfigs: ResolvedVpcConfig[] = []; // Add mandatory account VPC configuration first for (const [accountKey, accountConfig] of this.getMandatoryAccountConfigs()) { for (const vpcConfig of accountConfig.vpc || []) { - const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); + const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region, appendSuffix); vpcConfigs.push({ accountKey, vpcConfig, ouKey: accountConfig.ou, - lzaVpcName + lzaVpcName }); } } @@ -1349,9 +1349,9 @@ export class AcceleratorConfig { continue; } } - vpcConfig.lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); + vpcConfig.lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region, appendSuffix); if (vpcConfig['cidr-src'] === 'dynamic') { - const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region); + const lzaVpcName = createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region, appendSuffix); vpcConfigs.push({ ouKey, accountKey, @@ -1365,7 +1365,7 @@ export class AcceleratorConfig { ouKey, vpcConfig, excludeAccounts, - lzaVpcName: createLzaVpcName(vpcConfig.name, ouKey, vpcConfig.region), + lzaVpcName: createLzaVpcName(vpcConfig.name, ouKey, vpcConfig.region, appendSuffix), }); } } else { @@ -1374,7 +1374,7 @@ export class AcceleratorConfig { ouKey, accountKey: destinationAccountKey, vpcConfig, - lzaVpcName: createLzaVpcName(vpcConfig.name, destinationAccountKey, vpcConfig.region) + lzaVpcName: createLzaVpcName(vpcConfig.name, destinationAccountKey, vpcConfig.region, appendSuffix) }); } } @@ -1387,7 +1387,7 @@ export class AcceleratorConfig { accountKey, vpcConfig, ouKey: accountConfig.ou, - lzaVpcName: createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region), + lzaVpcName: createLzaVpcName(vpcConfig.name, accountKey, vpcConfig.region, appendSuffix), }); } } @@ -1395,8 +1395,8 @@ export class AcceleratorConfig { return vpcConfigs; } - getAzSubnets(accountKey: string, vpcName: string, subnetName: string) { - const vpcConfigs = this.getVpcConfigs(); + getAzSubnets(accountKey: string, vpcName: string, subnetName: string, appendSuffix: boolean) { + const vpcConfigs = this.getVpcConfigs(appendSuffix); const vpcConfig = vpcConfigs.find((v) => v.accountKey === accountKey && v.vpcConfig.name === vpcName)?.vpcConfig; if (!vpcConfig) { throw new Error(`VPC named "${vpcName}" not found in account "${accountKey}"`); @@ -1414,9 +1414,9 @@ export class AcceleratorConfig { } } -export function createLzaVpcName(vpcName: string, accountKey: string, region: string): string { +export function createLzaVpcName(vpcName: string, accountKey: string, region: string, appendSuffix: boolean): string { const md5Hash = crypto.createHash('md5').update(`${vpcName}_${accountKey}_${region}`).digest('hex'); const vpcNameWithType = vpcName.endsWith('_vpc') ? vpcName : `${vpcName}_vpc`; - const lzaVpcName = `${vpcNameWithType}..${md5Hash.substring(0,5)}`; + const lzaVpcName = appendSuffix ? `${vpcNameWithType}..${md5Hash.substring(0,5)}` : vpcNameWithType; return lzaVpcName; } \ No newline at end of file diff --git a/reference-artifacts/Custom-Scripts/lza-upgrade/src/config.ts b/reference-artifacts/Custom-Scripts/lza-upgrade/src/config.ts index 34bee359a..a6bdfcec0 100644 --- a/reference-artifacts/Custom-Scripts/lza-upgrade/src/config.ts +++ b/reference-artifacts/Custom-Scripts/lza-upgrade/src/config.ts @@ -36,4 +36,5 @@ export interface Config { skipDriftDetection?: boolean; localConfigFilePath?: string; enableTerminationProtection?: boolean; + appendUniqueSuffixToVPCNames?: boolean } diff --git a/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts b/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts index af921c3e8..5d78115f7 100644 --- a/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts +++ b/reference-artifacts/Custom-Scripts/lza-upgrade/src/convert-config.ts @@ -190,6 +190,7 @@ export class ConvertAseaConfig { private readonly assumeRoleName: string; private readonly writeFilesConfig: WriteToSourcesTypes.WriteToSourcesConfig; private readonly ouToNestedOuMap: Map> = new Map(); + private readonly appendVpcSuffixes: boolean; private accounts: Account[] = []; private outputs: StackOutput[] = []; private vpcAssignedCidrs: VpcAssignedCidr[] = []; @@ -213,6 +214,7 @@ export class ConvertAseaConfig { this.region = config.homeRegion; this.centralBucketName = config.centralBucket!; this.aseaPrefix = config.aseaPrefix!.endsWith('-') ? config.aseaPrefix! : `${config.aseaPrefix}-`; + this.appendVpcSuffixes = config.appendUniqueSuffixToVPCNames ?? false; this.parametersTable = `${this.aseaPrefix}Parameters`; this.acceleratorName = config.acceleratorName!; this.sts = new STS(); @@ -252,7 +254,7 @@ export class ConvertAseaConfig { this.subnetAssignedCidrs = await loadSubnetAssignedCidrs(subnetsCidrsTableName(this.aseaPrefix), this.dynamoDb); this.outputs = await loadOutputs(`${this.aseaPrefix}Outputs`, this.dynamoDb); this.globalOptions = aseaConfig['global-options']; - this.vpcConfigs = aseaConfig.getVpcConfigs(); + this.vpcConfigs = aseaConfig.getVpcConfigs(this.appendVpcSuffixes); const regionsWithVpc = this.vpcConfigs.map((resolvedConfig) => resolvedConfig.vpcConfig.region); this.regionsWithoutVpc = this.globalOptions['supported-regions'].filter( (region) => !regionsWithVpc.includes(region), @@ -2973,7 +2975,7 @@ export class ConvertAseaConfig { sourceVpcConfig = this.vpcConfigs.find(({ vpcConfig }) => vpcConfig.name === source.vpc); } if (SecurityGroupSourceConfig.is(source)) { - lzaRule.sources.push({ + lzaRule.sources.push({ securityGroups: source['security-group'].map(securityGroupName), }); } else if (SubnetSourceConfig.is(source)) { @@ -2985,7 +2987,7 @@ export class ConvertAseaConfig { ), subnets: source.subnet.flatMap((sourceSubnet) => aseaConfig - .getAzSubnets(sourceVpcConfig?.accountKey || source.account || accountKey || '', source.vpc, sourceSubnet) + .getAzSubnets(sourceVpcConfig?.accountKey || source.account || accountKey || '', source.vpc, sourceSubnet, this.appendVpcSuffixes) .map((s) => createSubnetName(source.vpc, s.subnetName, s.az)), ), vpc: sourceVpcConfig?.lzaVpcName ?? source.vpc, @@ -3065,7 +3067,7 @@ export class ConvertAseaConfig { target = { account: destinationAccountKey, subnet: createSubnetName(dest.vpc, ruleSubnet.subnetName, ruleSubnet.az), - vpc: createLzaVpcName(destination, destinationAccountKey!, vpcConfig.region), + vpc: createLzaVpcName(destination, destinationAccountKey!, vpcConfig.region, this.appendVpcSuffixes), region: targetRegion, }; } @@ -3212,7 +3214,7 @@ export class ConvertAseaConfig { if (inboundResolver) { lzaEndpointsConfig.push({ name: `${vpcConfig.name}InboundEndpoint`, - vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region), + vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region, this.appendVpcSuffixes), subnets: vpcConfig.subnets ?.find((subnetItem) => subnetItem.name === vpcConfig.resolvers?.subnet) @@ -3226,7 +3228,7 @@ export class ConvertAseaConfig { if (outboundResolver) { lzaEndpointsConfig.push({ name: `${vpcConfig.name}OutboundEndpoint`, - vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region), + vpc: createLzaVpcName(vpcConfig.name, accountKey!, vpcConfig.region, this.appendVpcSuffixes), subnets: vpcConfig.subnets ?.find((subnetItem) => subnetItem.name === vpcConfig.resolvers?.subnet) @@ -3725,7 +3727,7 @@ export class ConvertAseaConfig { return ipv4CidrBlock; } private async createCloudFormationStacksForALBIpForwarding(aseaConfig: AcceleratorConfig) { - const vpcs = aseaConfig.getVpcConfigs(); + const vpcs = aseaConfig.getVpcConfigs(this.appendVpcSuffixes); const vpcMaps = []; for (const vpc of vpcs) { if (vpc.vpcConfig['alb-forwarding']) { From 1f741f1e2082f0ce81c6d218b3bac54e106941ec Mon Sep 17 00:00:00 2001 From: Olivier Gaumond Date: Thu, 4 Sep 2025 17:26:34 -0400 Subject: [PATCH 3/3] update docuentation for duplicate VPC names --- src/mkdocs/docs/lza-upgrade/known-issues.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/mkdocs/docs/lza-upgrade/known-issues.md b/src/mkdocs/docs/lza-upgrade/known-issues.md index d5f56c37e..14c08cda9 100644 --- a/src/mkdocs/docs/lza-upgrade/known-issues.md +++ b/src/mkdocs/docs/lza-upgrade/known-issues.md @@ -68,6 +68,24 @@ cat network-config.yaml | yq '[.vpcs[] | select(.account == "shared-network" and **Resolution or workaround:** If resource synchronization issues are encountered, executing the LZA pipeline can be re-run from the beginning to synchronize resource mappings. +### Duplicate VPC Names + +**Description:** After converting the AESA to LZA configuration files you get an error about duplicate VPC names in LZA configuration validation. +> config-validator | network-config.yaml has 1 issues: Duplicate VPC/VPC template names exist. VPC names must be unique + +**Root cause:** The name of VPC names in LZA `network-config.yaml` need to be unique globally. + +**Resolution or workaround:** A workaround was implemented into LZA to support existing ASEA VPCs that have non-unique names across different accounts or regions. Suffixes in the form of `..uniquehash` can be added to the names of VPC (i.e. `Central_vpc..f7678`) in the LZA configurations files and all their references. LZA will remove the suffix at runtime to match with the existing VPC (`Central_vpc`). + +You can activate a configuration option in the upgrade tool to generate suffixes on all VPC references in the configuration. + +1. After running the `yarn migration-config` command from the [Preparation phase](./preparation/prereq-config/#configuration) +2. Edit the `src/input-config/input-config.json` file +3. Add the following property to enable the behavior: `"appendUniqueSuffixToVPCNames": true` +4. Continue with the remaining of the LZA upgrade steps. When running `yarn convert-config` with this option, suffixes will be appended to all VPCs from the configuration. + +**Note:** The existing VPC resources won't be renamed, the suffix is only used in the configuration. Some internal references will include the suffixes, such as SSM Parameters describing networking resources and path of VPC Flow Logs on S3. + ## Landing Zone Accelerator known issues The following issues will not prevent a successful upgrade from ASEA to LZA, but can impact functionalities and operations in the upgraded Landing Zone.