From 67f4ca81d9b1379af936d3e5402a6e59c600bfa4 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:32:03 -0400 Subject: [PATCH] fix(cis): require 3-of-3 periods for UnauthorizedAPICalls alarm (INFRA-104) (#25) The cis-UnauthorizedAPICalls alarm fired on a single breaching 5-min period (1/1), so any CloudFormation/CDK deploy burst of benign describe-API denials or a one-off console fat-finger paged and self-recovered, producing notification storms (~17 flips on 2026-06-10). Require 3 consecutive breaching periods so only sustained unauthorized activity alarms; CIS detection of a real persistent problem is preserved (detection window up to ~15 min). Per-control override so the other 14 CIS alarms keep their 1/1 sensitivity (templates untouched). GPT-4.1 cross-review: no blockers (documentation FIX noted re: detection latency). --- lib/cis-monitoring.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/cis-monitoring.ts b/lib/cis-monitoring.ts index af41368..34b5740 100644 --- a/lib/cis-monitoring.ts +++ b/lib/cis-monitoring.ts @@ -28,6 +28,11 @@ interface CisControl { readonly metricName: string; readonly pattern: string; readonly description: string; + // Optional alarm-sensitivity override. Defaults to 1/1 (page on a single + // breaching 5-min period) which suits low-frequency security signals. Raise + // for noisy high-volume metrics where one-off breaches are expected. + readonly evaluationPeriods?: number; + readonly datapointsToAlarm?: number; } const CIS_CONTROLS: CisControl[] = [ @@ -37,6 +42,14 @@ const CIS_CONTROLS: CisControl[] = [ pattern: '{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode = "AccessDenied*") && ($.sourceIPAddress != "delivery.logs.amazonaws.com") && ($.eventName != "HeadBucket") }', description: "CIS 4.1 — unauthorized API calls", + // This metric is high-volume: a single CloudFormation/CDK deploy can emit a + // burst of benign describe-API denials, and any one-off console fat-finger + // trips a 1/1 alarm and self-recovers, producing notification storms. Require + // 3 consecutive breaching 5-min periods so only *sustained* unauthorized + // activity (e.g. a misconfigured role failing every call) pages. Detection of + // a real persistent problem is preserved; transient bursts are filtered. + evaluationPeriods: 3, + datapointsToAlarm: 3, }, { id: "ConsoleSigninNoMfa", @@ -209,7 +222,10 @@ export class CisMonitoring extends Construct { threshold: 1, comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD, - evaluationPeriods: 1, + evaluationPeriods: c.evaluationPeriods ?? 1, + // Omitted (undefined) for default 1/1 controls so their templates are + // untouched; CloudWatch defaults datapointsToAlarm to evaluationPeriods. + datapointsToAlarm: c.datapointsToAlarm ?? c.evaluationPeriods, treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING, });