Skip to content

Commit c818f69

Browse files
fix(upgrade): disable ASEA subscription filter rules in the asea-prep step (#1244)
* fix(upgrade): disable EventBridge rule NewLogGroup_rule during asea prep * fix(upgrade): disable EventBridge rule NewLogGroup_rule during asea prep * fix(upgrade): disable EventBridge rule NewLogGroup_rule during asea prep * fix sts error * fix(upgrade): disable EventBridge rule NewLogGroup_rule during asea prep --------- Co-authored-by: hickeydh-aws <88673813+hickeydh-aws@users.noreply.github.com>
1 parent f11f080 commit c818f69

File tree

7 files changed

+153
-5
lines changed

7 files changed

+153
-5
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"tabWidth": 2,
3+
"printWidth": 120,
4+
"singleQuote": true,
5+
"trailingComma": "all",
6+
"arrowParens": "avoid"
7+
}

reference-artifacts/Custom-Scripts/lza-upgrade/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"lza-prep": "ts-node src/index.ts lza-prep",
2424
"post-migration": "ts-node src/index.ts post-migration",
2525
"migration-config": "ts-node src/index migration-config",
26+
"disable-subscription-rules": "ts-node src/index disable-rules",
2627
"all": "ts-node src/index migration-config; ts-node src/index snapshot pre"
2728
},
2829
"devDependencies": {

reference-artifacts/Custom-Scripts/lza-upgrade/src/common/utils/accounts.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313

1414
import { DynamoDB } from '../aws/dynamodb';
1515
import { Account } from '../outputs/accounts';
16+
import { STS } from '../aws/sts';
17+
18+
19+
export interface Environment {
20+
accountId: string;
21+
accountKey: string;
22+
region: string;
23+
}
1624

1725
export async function loadAccounts(tableName: string, client: DynamoDB): Promise<Account[]> {
1826
let index = 0;
@@ -31,3 +39,22 @@ export async function loadAccounts(tableName: string, client: DynamoDB): Promise
3139
}
3240
return accounts;
3341
}
42+
43+
export function getEnvironments(accounts: Account[], regions: string[]): Environment[] {
44+
const environments: Environment[] = [];
45+
for (const account of accounts) {
46+
for (const region of regions) {
47+
environments.push({
48+
accountId: account.id,
49+
accountKey: account.key,
50+
region,
51+
});
52+
}
53+
}
54+
return environments;
55+
}
56+
57+
export async function assumeRole(accountId: string, roleName: string) {
58+
const sts = new STS();
59+
return sts.getCredentialsForAccountAndRole(accountId, roleName);
60+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
5+
* with the License. A copy of the License is located at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* or in the 'license' file accompanying this file. This file is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES
10+
* OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*/
13+
14+
import { Account } from './common/outputs/accounts';
15+
import { DynamoDB } from './common/aws/dynamodb';
16+
import { Environment, getEnvironments, loadAccounts } from './common/utils/accounts';
17+
import { loadAseaConfig } from './asea-config/load';
18+
import { Config } from './config';
19+
import { AcceleratorConfig } from './asea-config';
20+
import { STS } from './common/aws/sts';
21+
import { throttlingBackOff } from './common/aws/backoff';
22+
import { EventBridgeClient, DisableRuleCommand, ResourceNotFoundException } from '@aws-sdk/client-eventbridge';
23+
24+
export class DisableRules {
25+
homeRegion: string;
26+
assumeRoleName: string;
27+
configRepositoryName: string;
28+
accountList: Account[];
29+
enabledRegions: string[];
30+
sts: STS;
31+
constructor(config: Config,
32+
disableRuleConfig: { accountList: Account[], enabledRegions: string[], acceleratorConfig: AcceleratorConfig },
33+
) {
34+
this.homeRegion = config.homeRegion;
35+
this.sts = new STS();
36+
this.assumeRoleName = config.assumeRoleName ?? 'OrganizationAccountAccessRole';
37+
this.configRepositoryName = config.repositoryName;
38+
this.accountList = disableRuleConfig.accountList;
39+
this.enabledRegions = disableRuleConfig.enabledRegions;
40+
}
41+
42+
static async init(config: Config) {
43+
const accountList = await loadAccounts(config.parametersTableName, new DynamoDB(undefined, config.homeRegion));
44+
const acceleratorConfig = await loadAseaConfig({
45+
filePath: 'raw/config.json',
46+
repositoryName: config.repositoryName,
47+
defaultRegion: config.homeRegion,
48+
});
49+
const enabledRegions = acceleratorConfig['global-options']['supported-regions'];
50+
const disableRules = new DisableRules(config, {accountList, enabledRegions, acceleratorConfig});
51+
return disableRules;
52+
}
53+
async disableAllAccountRules(prefix: string) {
54+
const environments = getEnvironments(this.accountList, this.enabledRegions);
55+
const eventBridgeClientMap = await this.getEventBridgeClientMap(environments);
56+
const deleteRulesPromises = environments.map(environment => this.disableEventBridgeRules(eventBridgeClientMap, environment.accountId, environment.region, prefix.replaceAll('-', '')));
57+
await Promise.all(deleteRulesPromises);
58+
}
59+
60+
async disableEventBridgeRules(eventBridgeClientMap: Map<string, EventBridgeClient>, accountId: string, region: string, prefix: string,){
61+
const client = eventBridgeClientMap.get(`${accountId}-${region}`);
62+
if (!client) {
63+
throw new Error(`No client found for account ${accountId} and region ${region}`);
64+
};
65+
const suffixes = [
66+
'NewLogGroup_rule'
67+
];
68+
for (const suffix of suffixes) {
69+
try {
70+
const command = new DisableRuleCommand({
71+
Name: `${prefix}-${suffix}`,
72+
});
73+
await throttlingBackOff (() => client.send(command));
74+
} catch (e: any) {
75+
if (e instanceof ResourceNotFoundException) {
76+
continue;
77+
}
78+
}
79+
console.log(`Disabling rule ${prefix}-${suffix} in ${accountId}-${region}`);
80+
}
81+
}
82+
83+
async getEventBridgeClientMap(environments: Environment[]) {
84+
const eventBridgeClientMap = new Map<string, EventBridgeClient>();
85+
const promises = [];
86+
for (const environment of environments) {
87+
promises.push(this.createEventBridgeClients(this.assumeRoleName, environment.accountId, environment.region));
88+
}
89+
const eventBridgeClients = await Promise.all(promises);
90+
eventBridgeClients.forEach((client) => {
91+
eventBridgeClientMap.set(`${client.accountId}-${client.region}`, client.client);
92+
});
93+
return eventBridgeClientMap;
94+
}
95+
96+
async createEventBridgeClients(assumeRoleName: string, accountId: string, region: string) {
97+
const credentials = await this.sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
98+
const client = new EventBridgeClient({ credentials, region });
99+
return {
100+
accountId,
101+
region,
102+
client,
103+
};
104+
}
105+
}

reference-artifacts/Custom-Scripts/lza-upgrade/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { PostMigration } from './post-migration';
2020
import { Preparation } from './preparation';
2121
import { ResourceMapping } from './resource-mapping';
2222
import { Snapshot } from './snapshot';
23+
import { DisableRules } from './disable-rules';
2324

2425
async function main() {
2526
const args = process.argv.slice(2);
@@ -49,6 +50,8 @@ async function main() {
4950
case 'asea-prep':
5051
const preparation = new Preparation(config);
5152
await preparation.prepareAsea();
53+
const disableRulesInPrep = await DisableRules.init(config);
54+
await disableRulesInPrep.disableAllAccountRules(config.aseaPrefix);
5255
break;
5356
case 'lza-prep':
5457
const lzaPreparation = new Preparation(config);
@@ -71,6 +74,10 @@ async function main() {
7174
break;
7275
}
7376
break;
77+
case 'disable-rules':
78+
const disableRules = await DisableRules.init(config);
79+
await disableRules.disableAllAccountRules(config.aseaPrefix);
80+
break;
7481
case 'post-migration':
7582
await new PostMigration(config, args).process();
7683
break;

reference-artifacts/Custom-Scripts/lza-upgrade/src/preparation/asea.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export async function disableASEARules(prefix: string) {
227227
'CreateOrganizationalUnit_rule',
228228
'MoveAccount_rule',
229229
'PolicyChanges_rule',
230-
'RemoveAccount_rule',
230+
'RemoveAccount_rule'
231231
];
232232

233233
const disableRuleCommands: DisableRuleCommand[] = suffixes.map((suffix) => {

reference-artifacts/Custom-Scripts/lza-upgrade/src/snapshot/snapshotConfiguration.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ export async function snapshotConfiguration(
8989
}
9090
}
9191

92-
async function getCredentials(accountId: string, roleName: string): Promise<AwsCredentialIdentity | undefined> {
92+
export async function getCredentials(accountId: string, roleName: string): Promise<AwsCredentialIdentity | undefined> {
93+
const stsClient = new STSClient({ maxAttempts: 10 });
9394
let stsResponse: AssumeRoleCommandOutput;
9495
try {
9596
stsResponse = await stsClient.send(
@@ -105,13 +106,13 @@ async function getCredentials(accountId: string, roleName: string): Promise<AwsC
105106
sessionToken: stsResponse.Credentials?.SessionToken!,
106107
};
107108
return credentials;
108-
} catch (e) {
109+
} catch (e: any) {
109110
console.error(`Failed to assume role ${roleName} in account ${accountId}`);
110-
return undefined;
111+
throw new Error(e);
111112
}
112113
}
113114

114-
async function getAccountList(): Promise<Account[]> {
115+
export async function getAccountList(): Promise<Account[]> {
115116
const organizationsClient = new OrganizationsClient({ region: 'us-east-1', maxAttempts: 10 });
116117

117118
const accounts: Account[] = [];

0 commit comments

Comments
 (0)