From 00626f1fc7e3a6d284624ca07b72d70f6399b8cf Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 28 Sep 2026 16:07:57 +0000 Subject: [PATCH] fix(iam): skip sanctioned org-admin assumes in the alarm (SEC-37) Count failed assumes for every principal. Do not page on a successful assume by the Platform permission set or the two repo script sessions. Co-authored-by: Adam Moussa --- lib/cis-monitoring.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lib/cis-monitoring.ts b/lib/cis-monitoring.ts index 2d9ff7f..9a415f7 100644 --- a/lib/cis-monitoring.ts +++ b/lib/cis-monitoring.ts @@ -264,16 +264,29 @@ export class CisMonitoring extends Construct { alarm.addAlarmAction(new cwactions.SnsAction(topic)); } - // SEC-37. Not a CIS control. Counts every AssumeRole of - // OrganizationAccountAccessRole, including failures. Same topic as the - // CIS alarms. SCP exemptions for that role stay in place. + // SEC-37. Not a CIS control. Same topic as the CIS alarms. + // SCP exemptions for OrganizationAccountAccessRole stay in place. + // + // A 1/1 alarm on every assume would page for each Platform operator + // session and each run of the bootstrap and substrate scripts. CIS 4.1 + // treats that single-event paging on a routine path as alert fatigue. + // Successful assumes are excluded only for those callers: + // * the Platform permission set (AWSReservedSSO_Platform_*) + // * session plat-145-hcptf-bootstrap (create-hcptf-bootstrap-roles.sh) + // * session plat-147-tf-substrate (delete-terraform-substrate-prod-dev.sh) + // Any errorCode still counts, including a failed call from those callers. + // + // Residual: roleSessionName is chosen by the caller, so a successful + // assume that copies one of those two session names is not counted. + // The scripts stay on OrganizationAccountAccessRole until the permission + // set is deployed and a real sign-in has assumed the member role. const orgAdminAssume = new logs.MetricFilter( this, "OrganizationAccountAccessRoleAssumeFilter", { logGroup, filterPattern: logs.FilterPattern.literal( - '{ ($.eventName = "AssumeRole") && ($.requestParameters.roleArn = "*OrganizationAccountAccessRole") }', + '{ ($.eventName = "AssumeRole") && ($.requestParameters.roleArn = "*OrganizationAccountAccessRole") && (($.errorCode = "*") || (($.userIdentity.arn != "*AWSReservedSSO_Platform_*") && ($.requestParameters.roleSessionName != "plat-145-hcptf-bootstrap") && ($.requestParameters.roleSessionName != "plat-147-tf-substrate"))) }', ), metricNamespace: "SeahavenSecurity", metricName: "OrganizationAccountAccessRoleAssume", @@ -289,7 +302,7 @@ export class CisMonitoring extends Construct { .createAlarm(this, "OrganizationAccountAccessRoleAssumeAlarm", { alarmName: "organization-account-access-role-assume", alarmDescription: - "AssumeRole of OrganizationAccountAccessRole, including failed attempts", + "AssumeRole of OrganizationAccountAccessRole outside the Platform permission set and the two repo script sessions. Failed attempts count for every principal.", threshold: 1, comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,