Unauthorized API calls alarm
Check ID: aws-cw-002
AWS-CW-002 is an AWS security check performed by cloud-audit, an open-source AWS security scanner. Checks if a CloudWatch metric filter and alarm exist to detect unauthorized API calls (AccessDenied, UnauthorizedAccess). Without this monitoring, credential probing goes undetected.
Why it matters
A spike in AccessDenied errors is one of the earliest indicators of credential compromise, where an attacker is systematically probing which APIs the stolen credentials can call. During the SolarWinds supply chain attack (2020), defenders who had unauthorized API call monitoring detected anomalous access patterns days before the breach was publicly disclosed. This alarm also catches misconfigurations where applications or CI/CD pipelines are calling APIs they should not have access to, revealing potential privilege escalation paths. Without this monitoring, attackers can quietly enumerate your environment permissions until they find an exploitable path.
Common causes
Teams that enable CloudTrail assume that logging alone provides detection capability, without realizing that logs sitting in S3 are only useful for post-incident forensics. Setting up CloudWatch metric filters requires understanding CloudTrail JSON log format and filter pattern syntax, which is a barrier for teams without dedicated security engineering. Organizations using third-party SIEM tools may skip CloudWatch alarms, not realizing that SIEM ingestion delays can miss time-sensitive alerts.
Detection
Run cloud-audit to detect this issue:
pip install cloud-audit
cloud-audit scan -R The -R flag includes remediation details for every finding, including this one.
Remediation: AWS CLI
# Create metric filter:
aws logs put-metric-filter \
--log-group-name <CLOUDTRAIL_LOG_GROUP> \
--filter-name CIS-4.1 \
--filter-pattern '{ ($.errorCode = "*UnauthorizedAccess*") || ($.errorCode = "AccessDenied*") }' \
--metric-transformations metricName=CIS-4-1,metricNamespace=CISBenchmark,metricValue=1
# Create alarm:
aws cloudwatch put-metric-alarm \
--alarm-name CIS-4.1 \
--metric-name CIS-4-1 \
--namespace CISBenchmark \
--statistic Sum --period 300 --threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 \
--alarm-actions <SNS_TOPIC_ARN> Remediation: Terraform
resource "aws_cloudwatch_log_metric_filter" "cis_4_1" {
name = "CIS-4.1"
log_group_name = aws_cloudwatch_log_group.cloudtrail.name
pattern = "{ ($.errorCode = \"*UnauthorizedAccess*\") || ($.errorCode = \"AccessDenied*\") }"
metric_transformation {
name = "CIS-4-1"
namespace = "CISBenchmark"
value = "1"
}
}
resource "aws_cloudwatch_metric_alarm" "cis_4_1" {
alarm_name = "CIS-4.1"
metric_name = "CIS-4-1"
namespace = "CISBenchmark"
statistic = "Sum"
period = 300
threshold = 1
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
alarm_actions = [aws_sns_topic.alerts.arn]
} Compliance mapping
This check maps to CIS 4.1 in the CIS AWS Foundations Benchmark. The CIS Benchmark provides prescriptive guidance for configuring security options for a subset of AWS services.
This check is part of cloud-audit - install with pip install cloud-audit
Related article
CIS AWS v3.0 in 60 Seconds: Automate Compliance with Terraform →