Check ID: cloudwatch_log_metric_filter_policy_changes
Provider: AWS
Service: cloudwatch
Severity: MEDIUM
Categories: logging
Resource type: AwsCloudWatchAlarm

What this check verifies

CloudWatch uses a metric filter and alarm to track IAM policy changes recorded by CloudTrail (e.g., CreatePolicy, DeletePolicy, version changes, inline policy edits, policy attach/detach). This finding reflects whether that filter and an associated alarm are present on the trail’s log group.

Risk

Absent alerting on IAM policy changes, privilege modifications can go unnoticed, enabling privilege escalation, hidden backdoors, or permission revocations. This threatens confidentiality and integrity, and may impact availability if critical access is removed or misconfigured.

Recommendation

Create a metric filter for IAM policy create/update/delete and attach/detach events with an alarm to notify responders.
  • Enforce least privilege and separation of duties for policy changes
  • Require approvals and central logging across Regions/accounts
  • Integrate alerts with incident response

Remediation

# Terraform: Metric filter and alarm for IAM policy changes
resource "aws_cloudwatch_log_metric_filter" "<example_resource_name>" {
  name           = "<example_resource_name>"
  log_group_name = "<example_resource_name>"  # CloudTrail log group

  # CRITICAL: Pattern matching IAM policy change events required by the check
  pattern = "{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}"

  metric_transformation {
    name      = "<example_resource_name>"      # CRITICAL: Metric created from filter
    namespace = "CISBenchmark"                 # CRITICAL: Namespace for the metric
    value     = "1"
  }
}

resource "aws_cloudwatch_metric_alarm" "<example_resource_name>" {
  alarm_name          = "<example_resource_name>"
  # CRITICAL: Alarm on the metric when >= 1 event occurs
  metric_name         = aws_cloudwatch_log_metric_filter.<example_resource_name>.metric_transformation[0].name
  namespace           = aws_cloudwatch_log_metric_filter.<example_resource_name>.metric_transformation[0].namespace
  statistic           = "Sum"
  period              = 300
  evaluation_periods  = 1
  threshold           = 1
  comparison_operator = "GreaterThanOrEqualToThreshold"
}

References

Where this check fires

This check runs on every scheduled scan against your AWS account. Findings appear at Cloud Security → Findings filterable by Check ID = cloudwatch_log_metric_filter_policy_changes. To re-evaluate after a fix, hit Run now on the account’s schedule under Cloud Security → Schedules — the next scan re-checks this control and marks the finding fixed or keeps it persistent.
← Back to AWS checks