CloudWatch Alarm for VPC Changes
Overview
This check verifies that your AWS account has a CloudWatch Logs metric filter and alarm configured to detect changes to Virtual Private Clouds (VPCs). It monitors CloudTrail events for VPC modifications including creating, deleting, or modifying VPCs and VPC peering connections.
When someone creates, deletes, or changes a VPC, you want to know about it. This alarm gives you that visibility.
Risk
Without monitoring VPC changes, unauthorized or accidental network modifications can go undetected. This creates serious security gaps:
- Data exposure: A VPC peering connection to an untrusted account could allow data exfiltration
- Lateral movement: Attackers who gain access might modify VPC attributes to expand their reach
- Service disruption: Accidental VPC deletions or misconfigurations can cause outages
- Compliance violations: Many frameworks require monitoring of network infrastructure changes
VPCs form the foundation of your network security. Changes to them deserve immediate attention.
Remediation Steps
Prerequisites
You need:
- AWS Console access with permissions to create CloudWatch metric filters and alarms
- An existing CloudTrail trail that sends logs to CloudWatch Logs
Required IAM permissions (for administrators)
Your IAM user or role needs these permissions:
logs:PutMetricFilterlogs:DescribeMetricFilterslogs:DescribeLogGroupscloudwatch:PutMetricAlarmcloudwatch:DescribeAlarmssns:CreateTopic(if creating a new notification topic)sns:Subscribe(if subscribing to notifications)
Setting up CloudTrail to CloudWatch Logs (if not already configured)
If your CloudTrail trail is not yet sending logs to CloudWatch Logs, you need to set this up first. See the cloudtrail_cloudwatch_logging_enabled remediation guide for detailed instructions.
AWS Console Method
Step 1: Create an SNS Topic for Notifications
- Go to Amazon SNS Console in us-east-1
- Click Topics in the left sidebar
- Click Create topic
- Select Standard type
- Enter a name like
vpc-changes-alarm - Click Create topic
- Click Create subscription
- Choose Email as the protocol
- Enter your email address
- Click Create subscription
- Check your email and confirm the subscription
Step 2: Create a Metric Filter
- Go to CloudWatch Console in us-east-1
- Click Log groups under Logs in the left sidebar
- Find and click on your CloudTrail log group (often named
/aws/cloudtrail/<trail-name>) - Click the Metric filters tab
- Click Create metric filter
- In the Filter pattern field, paste this pattern:
{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }
- Click Next
- Enter filter name:
VPCChangesMetricFilter - Enter metric namespace:
CISBenchmark - Enter metric name:
vpc_changes_metric - Enter metric value:
1 - Leave default value as
0 - Click Next, then Create metric filter
Step 3: Create an Alarm
- Still in CloudWatch, click All alarms under Alarms in the left sidebar
- Click Create alarm
- Click Select metric
- Navigate to CISBenchmark > Metrics with no dimensions
- Select
vpc_changes_metric - Click Select metric
- Configure the alarm:
- Statistic: Sum
- Period: 5 minutes
- Threshold type: Static
- Whenever vpc_changes_metric is: Greater/Equal than 1
- Click Next
- For notification:
- Select In alarm
- Choose Select an existing SNS topic
- Select your
vpc-changes-alarmtopic
- Click Next
- Enter alarm name:
VPCChangesAlarm - Enter description:
Alarm triggered when VPC configuration changes are detected - Click Next, then Create alarm
AWS CLI (optional)
Step 1: Create an SNS Topic
aws sns create-topic \
--name vpc-changes-alarm \
--region us-east-1
Note the TopicArn in the output (format: arn:aws:sns:us-east-1:<account-id>:vpc-changes-alarm).
Subscribe your email:
aws sns subscribe \
--topic-arn arn:aws:sns:us-east-1:<your-account-id>:vpc-changes-alarm \
--protocol email \
--notification-endpoint your-email@example.com \
--region us-east-1
Step 2: Create the Metric Filter
Replace <your-cloudtrail-log-group> with your CloudTrail log group name:
aws logs put-metric-filter \
--log-group-name <your-cloudtrail-log-group> \
--filter-name VPCChangesMetricFilter \
--filter-pattern '{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }' \
--metric-transformations metricName=vpc_changes_metric,metricNamespace=CISBenchmark,metricValue=1,defaultValue=0 \
--region us-east-1
Step 3: Create the CloudWatch Alarm
aws cloudwatch put-metric-alarm \
--alarm-name VPCChangesAlarm \
--alarm-description "Alarm triggered when VPC configuration changes are detected" \
--metric-name vpc_changes_metric \
--namespace CISBenchmark \
--statistic Sum \
--period 300 \
--evaluation-periods 1 \
--threshold 1 \
--comparison-operator GreaterThanOrEqualToThreshold \
--alarm-actions arn:aws:sns:us-east-1:<your-account-id>:vpc-changes-alarm \
--treat-missing-data notBreaching \
--region us-east-1
CloudFormation (optional)
This template creates the complete monitoring setup including SNS topic, metric filter, and alarm:
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudWatch alarm for VPC changes (CIS Benchmark)
Parameters:
CloudTrailLogGroupName:
Type: String
Description: Name of the CloudTrail CloudWatch Logs log group
Default: /aws/cloudtrail/my-trail
NotificationEmail:
Type: String
Description: Email address for alarm notifications
AllowedPattern: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
ConstraintDescription: Must be a valid email address
Resources:
VPCChangesSnsTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: vpc-changes-alarm
DisplayName: VPC Changes Alarm
VPCChangesEmailSubscription:
Type: AWS::SNS::Subscription
Properties:
TopicArn: !Ref VPCChangesSnsTopic
Protocol: email
Endpoint: !Ref NotificationEmail
VPCChangesMetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
LogGroupName: !Ref CloudTrailLogGroupName
FilterName: VPCChangesMetricFilter
FilterPattern: >-
{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) ||
($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) ||
($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) ||
($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) ||
($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) ||
($.eventName = EnableVpcClassicLink) }
MetricTransformations:
- MetricName: vpc_changes_metric
MetricNamespace: CISBenchmark
MetricValue: '1'
DefaultValue: 0
VPCChangesAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
AlarmName: VPCChangesAlarm
AlarmDescription: Alarm triggered when VPC configuration changes are detected
MetricName: vpc_changes_metric
Namespace: CISBenchmark
Statistic: Sum
Period: 300
EvaluationPeriods: 1
Threshold: 1
ComparisonOperator: GreaterThanOrEqualToThreshold
TreatMissingData: notBreaching
AlarmActions:
- !Ref VPCChangesSnsTopic
Outputs:
AlarmArn:
Description: ARN of the VPC changes alarm
Value: !GetAtt VPCChangesAlarm.Arn
SnsTopicArn:
Description: ARN of the SNS topic for notifications
Value: !Ref VPCChangesSnsTopic
Deploy with:
aws cloudformation deploy \
--template-file vpc-changes-alarm.yaml \
--stack-name vpc-changes-monitoring \
--parameter-overrides \
CloudTrailLogGroupName=/aws/cloudtrail/my-trail \
NotificationEmail=your-email@example.com \
--region us-east-1
Terraform (optional)
# Variables
variable "cloudtrail_log_group_name" {
description = "Name of the CloudTrail CloudWatch Logs log group"
type = string
default = "/aws/cloudtrail/my-trail"
}
variable "notification_email" {
description = "Email address for alarm notifications"
type = string
}
# SNS Topic for notifications
resource "aws_sns_topic" "vpc_changes" {
name = "vpc-changes-alarm"
display_name = "VPC Changes Alarm"
}
resource "aws_sns_topic_subscription" "vpc_changes_email" {
topic_arn = aws_sns_topic.vpc_changes.arn
protocol = "email"
endpoint = var.notification_email
}
# Metric filter for VPC changes
resource "aws_cloudwatch_log_metric_filter" "vpc_changes" {
name = "VPCChangesMetricFilter"
pattern = "{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) || ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection) || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection) || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc) || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink) || ($.eventName = EnableVpcClassicLink) }"
log_group_name = var.cloudtrail_log_group_name
metric_transformation {
name = "vpc_changes_metric"
namespace = "CISBenchmark"
value = "1"
default_value = "0"
}
}
# CloudWatch alarm
resource "aws_cloudwatch_metric_alarm" "vpc_changes" {
alarm_name = "VPCChangesAlarm"
alarm_description = "Alarm triggered when VPC configuration changes are detected"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "vpc_changes_metric"
namespace = "CISBenchmark"
period = 300
statistic = "Sum"
threshold = 1
treat_missing_data = "notBreaching"
alarm_actions = [aws_sns_topic.vpc_changes.arn]
depends_on = [aws_cloudwatch_log_metric_filter.vpc_changes]
}
# Outputs
output "alarm_arn" {
description = "ARN of the VPC changes alarm"
value = aws_cloudwatch_metric_alarm.vpc_changes.arn
}
output "sns_topic_arn" {
description = "ARN of the SNS topic for notifications"
value = aws_sns_topic.vpc_changes.arn
}
Deploy with:
terraform init
terraform plan -var="notification_email=your-email@example.com"
terraform apply -var="notification_email=your-email@example.com"
Verification
After setting up the alarm, verify everything is working:
-
Check the metric filter exists:
- Go to CloudWatch > Log groups > your CloudTrail log group
- Click the Metric filters tab
- Verify
VPCChangesMetricFilterappears in the list
-
Check the alarm is configured:
- Go to CloudWatch > All alarms
- Find
VPCChangesAlarm - Verify status shows OK or Insufficient data (not In alarm unless there were recent VPC changes)
-
Test the alarm (optional):
- Create a test VPC in the console or CLI
- Wait 5-10 minutes
- Check that you receive an email notification
- Delete the test VPC when done
CLI verification commands
Check if the metric filter exists:
aws logs describe-metric-filters \
--log-group-name <your-cloudtrail-log-group> \
--filter-name-prefix VPCChanges \
--region us-east-1
Check if the alarm exists and its state:
aws cloudwatch describe-alarms \
--alarm-names VPCChangesAlarm \
--region us-east-1 \
--query 'MetricAlarms[0].{Name:AlarmName,State:StateValue,Metric:MetricName}'
Expected output shows the alarm exists with StateValue of OK or INSUFFICIENT_DATA.
Additional Resources
- AWS Documentation: Creating CloudWatch Alarms for CloudTrail Events
- AWS Documentation: Filter and Pattern Syntax
- CIS AWS Foundations Benchmark
- AWS VPC Documentation
Notes
-
CloudTrail requirement: This alarm requires CloudTrail to be configured to send logs to CloudWatch Logs. If you see "Insufficient data" for extended periods, verify your CloudTrail integration is working.
-
False positives: Legitimate VPC changes (like creating new environments) will trigger this alarm. Consider this expected behavior - the goal is visibility, not necessarily blocking changes.
-
Multiple alarms: For comprehensive CIS Benchmark compliance, you may need similar alarms for other resource types (security groups, network ACLs, route tables, etc.).
-
Costs: CloudWatch alarms and metric filters have minimal cost, but consider the volume of CloudTrail logs and any additional log storage costs.
-
Classic Link events: The filter includes VPC Classic Link events. If you don't use EC2-Classic (most accounts don't), these events won't occur, but including them ensures complete coverage.
-
Response procedures: Consider documenting what actions to take when this alarm fires, such as identifying who made the change and whether it was authorized.