Skip to content
This repository was archived by the owner on Dec 31, 2025. It is now read-only.

Commit 67be0e5

Browse files
authored
retries implemented for gd and macie. (#779) (#780)
Authored-by: Dustin Hickey <hickeydh@amazon.amazon.com>
1 parent cad63b0 commit 67be0e5

4 files changed

Lines changed: 89 additions & 60 deletions

File tree

src/deployments/cdk/src/deployments/iam/guardduty-roles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export async function createAdminRole(stack: AccountStack) {
4747

4848
role.addToPrincipalPolicy(
4949
new iam.PolicyStatement({
50-
actions: ['guardduty:EnableOrganizationAdminAccount'],
50+
actions: ['guardduty:EnableOrganizationAdminAccount', 'guardduty:ListOrganizationAdminAccounts'],
5151
resources: ['*'],
5252
}),
5353
);

src/deployments/cdk/src/deployments/iam/macie-roles.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export async function createMacieAdminRole(stack: AccountStack) {
6060
);
6161
role.addToPrincipalPolicy(
6262
new iam.PolicyStatement({
63-
actions: ['macie2:EnableOrganizationAdminAccount'],
63+
actions: ['macie2:EnableOrganizationAdminAccount', 'macie2:ListOrganizationAdminAccounts'],
6464
resources: ['*'],
6565
}),
6666
);

src/lib/custom-resources/cdk-guardduty-enable-admin/runtime/src/index.ts

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,41 +29,61 @@ async function onEvent(event: CloudFormationCustomResourceEvent) {
2929
}
3030
}
3131

32-
function getPhysicalId(event: CloudFormationCustomResourceEvent): string {
33-
const properties = (event.ResourceProperties as unknown) as HandlerProperties;
34-
35-
return `${properties.accountId}`;
36-
}
37-
3832
async function onCreateOrUpdate(
3933
event: CloudFormationCustomResourceCreateEvent | CloudFormationCustomResourceUpdateEvent,
4034
) {
41-
const properties = (event.ResourceProperties as unknown) as HandlerProperties;
42-
const response = await enableOrgAdmin(properties);
35+
const accountId = event.ResourceProperties.accountId;
36+
const sleepTime = 30000;
37+
const retryCount = 10;
38+
await enableOrgAdmin(accountId);
39+
let guardDutyAdminEnabled = await isGuardDutyAdminEnabled(accountId);
40+
let retries = 0;
41+
while (!guardDutyAdminEnabled && retries < retryCount) {
42+
console.log(
43+
`GuardDuty Admin not enabled. Retrying in ${sleepTime / 1000} seconds. Retry: ${retries + 1} of ${retryCount}`,
44+
);
45+
await sleep(sleepTime);
46+
await enableOrgAdmin(accountId);
47+
guardDutyAdminEnabled = await isGuardDutyAdminEnabled(accountId);
48+
retries++;
49+
}
4350
return {
44-
physicalResourceId: getPhysicalId(event),
51+
physicalResourceId: event.ResourceProperties.accountId,
4552
data: {},
4653
};
4754
}
55+
async function isGuardDutyAdminEnabled(accountId: string) {
56+
console.log(`Checking if GuardDuty Administration is enabled for account ${accountId}`);
57+
const adminList = await guardduty.listOrganizationAdminAccounts().promise();
58+
console.log(adminList);
59+
const isAccountAdded = adminList.AdminAccounts?.filter(account => {
60+
return account.AdminAccountId === accountId;
61+
});
62+
63+
if (isAccountAdded!.length === 0) {
64+
console.log('Account has not been added.');
65+
} else {
66+
console.log('Account has been added.');
67+
}
68+
return isAccountAdded!.length > 0;
69+
}
4870

49-
async function enableOrgAdmin(properties: HandlerProperties) {
71+
async function sleep(ms: number) {
72+
return new Promise(resolve => setTimeout(resolve, ms));
73+
}
74+
75+
async function enableOrgAdmin(accountId: string) {
5076
const params = {
51-
AdminAccountId: properties.accountId,
77+
AdminAccountId: accountId,
5278
};
5379

5480
try {
55-
const enableAdmin = await throttlingBackOff(() => guardduty.enableOrganizationAdminAccount(params).promise());
56-
81+
console.log(`Enabling GuardDuty Admin for account ${accountId}`);
82+
const enableAdmin = await guardduty.enableOrganizationAdminAccount(params).promise();
83+
console.log(enableAdmin);
5784
return enableAdmin;
5885
} catch (e) {
59-
const message = `${e}`;
60-
// if account is already enabled as delegated admin, do not error out
61-
if (
62-
message.includes(`the account is already enabled as the GuardDuty delegated administrator for the organization`)
63-
) {
64-
console.warn(message);
65-
} else {
66-
throw e;
67-
}
86+
console.log('Could not enable Guard Duty Admin.');
87+
console.log(e);
6888
}
6989
}

src/lib/custom-resources/cdk-macie-enable-admin/runtime/src/index.ts

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
CloudFormationCustomResourceUpdateEvent,
77
} from 'aws-lambda';
88
import { errorHandler } from '@aws-accelerator/custom-resource-runtime-cfn-response';
9-
import { throttlingBackOff } from '@aws-accelerator/custom-resource-cfn-utils';
109

1110
const macie = new AWS.Macie2();
1211

@@ -31,50 +30,60 @@ async function onEvent(event: CloudFormationCustomResourceEvent) {
3130
}
3231
}
3332

34-
function getPhysicalId(event: CloudFormationCustomResourceEvent): string {
35-
const properties = (event.ResourceProperties as unknown) as HandlerProperties;
36-
37-
return `${properties.accountId}`;
38-
}
39-
4033
async function onCreateOrUpdate(
4134
event: CloudFormationCustomResourceCreateEvent | CloudFormationCustomResourceUpdateEvent,
4235
) {
43-
const properties = (event.ResourceProperties as unknown) as HandlerProperties;
44-
const response = await enableOrgAdmin(properties);
36+
const accountId = event.ResourceProperties.accountId;
37+
const sleepTime = 30000;
38+
const retryCount = 10;
39+
await enableOrgAdmin(accountId);
40+
let macieAdminEnabled = await isMacieAdminEnabled(accountId);
41+
let retries = 0;
42+
while (!macieAdminEnabled && retries < retryCount) {
43+
console.warn(
44+
`Macie Admin not enabled. Retrying in ${sleepTime / 1000} seconds. Retry: ${retries + 1} of ${retryCount}`,
45+
);
46+
await sleep(sleepTime);
47+
await enableOrgAdmin(accountId);
48+
macieAdminEnabled = await isMacieAdminEnabled(accountId);
49+
retries++;
50+
}
4551
return {
46-
physicalResourceId: getPhysicalId(event),
52+
physicalResourceId: accountId,
4753
data: {},
4854
};
4955
}
5056

51-
async function enableOrgAdmin(properties: HandlerProperties) {
52-
try {
53-
const enableAdmin = await throttlingBackOff(() =>
54-
macie
55-
.enableOrganizationAdminAccount({
56-
adminAccountId: properties.accountId,
57-
})
58-
.promise(),
59-
);
57+
async function isMacieAdminEnabled(accountId: string) {
58+
console.log(`Checking if Macie Administration is enabled for account ${accountId}`);
59+
const adminList = await macie.listOrganizationAdminAccounts().promise();
60+
const isAccountAdded = adminList.adminAccounts?.filter(account => {
61+
return account.accountId === accountId;
62+
});
63+
if (isAccountAdded!.length === 0) {
64+
console.log('Account has not been added.');
65+
} else {
66+
console.log('Account has been added.');
67+
}
68+
return isAccountAdded!.length > 0;
69+
}
6070

61-
return enableAdmin;
71+
async function enableOrgAdmin(accountId: string) {
72+
console.info(`Enabling Macie Admin Account ${accountId}`);
73+
try {
74+
const macieAdmin = await macie
75+
.enableOrganizationAdminAccount({
76+
adminAccountId: accountId,
77+
})
78+
.promise();
79+
console.info(macieAdmin);
6280
} catch (e) {
63-
const message = `${e}`;
64-
if (
65-
message.includes(
66-
'The request failed because an account is already enabled as the Macie delegated administrator for the organization',
67-
)
68-
) {
69-
console.warn(e);
70-
} else if (
71-
message.includes(
72-
`The request failed because there's already a delegated Macie administrator account for your organization`,
73-
)
74-
) {
75-
console.warn(e);
76-
} else {
77-
throw e;
78-
}
81+
console.warn('Could not enable Macie Admin account');
82+
console.warn(e);
83+
return;
7984
}
8085
}
86+
87+
async function sleep(ms: number) {
88+
return new Promise(resolve => setTimeout(resolve, ms));
89+
}

0 commit comments

Comments
 (0)