Control: 4.13 Ensure a log metric filter and alarm exist for route table changes
Description
Real-time monitoring of API calls can be achieved by directing CloudTrail Logs to CloudWatch Logs and establishing corresponding metric filters and alarms. Network gateways are required to send/receive traffic to a destination outside of a VPC. It is recommended that a metric filter and alarm be established for changes to network gateways.
Monitoring changes to network gateways will help ensure that all ingress/egress traffic traverses the VPC border via a controlled path.
Remediation
The steps to remediate this issue include setting up an Amazon SNS topic, a metric filter, and an alarm for the metric filter.
From Console
To create SNS topic
- Open the Amazon SNS console at SNS.
 - Create an Amazon SNS topic that receives all CIS alarms. Create at least one subscriber to the topic. You can follow steps here
 - Set up an active CloudTrail that applies to all Regions. To do so, follow the remediation steps in CIS 3.1 – Ensure CloudTrail is enabled in all Regions.
 - Make a note of the associated log group name.
 
To create a metric filter and alarm
- Open the CloudWatch console at CloudWatch.
 - In the navigation pane, choose Log groups.
 - Select the check box for the log group that you made a note of in the previous step (4).
 - From Actions, choose Create Metric Filter.
 - Under Define pattern, do the following:
- Copy the following pattern and then paste it into the Filter Pattern field.{ ($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }"
 - Choose Next.
 
 - Copy the following pattern and then paste it into the Filter Pattern field.
 - Under Assign metric, do the following:
- In Filter name, enter a name for your metric filter.
 - For Metric namespace, enter 
CISBenchmark. You can use the same namespace for all of your CIS log metric filters. - For Metric name, enter a name for the metric.
 - The name of the metric is required to create the alarm.
 - For Metric value, enter 1.
 - Choose Next.
 
 - Under Review and create, review the details and choose Create metric filter.
 - Choose the Metric filters tab, select the metric filter that you just created.
 - To choose the metric filter, select the 
check boxat the upper right. - Choose Create Alarm.
 - Follow the steps provided in Create an alarm
 - Under Configure actions, do the following:
- Under Alarm state trigger, choose In alarm.
 - Under Select an SNS topic, choose Select an existing SNS topic.
 - For Send a notification to, enter the name of the SNS topic that you created in the previous procedure.
 - Choose Next.
 
 - Under Add name and description, enter a Name and Description for the alarm. For example, CIS4.13-[SmallDescription]. Then choose Next.
 - Under Preview and create, review the alarm configuration. Choose Create alarm.
 
From Command Line
Perform the following to setup the metric filter, alarm, SNS topic, and subscription
- Create a metric filter based on filter pattern provided and CloudWatch log group.
 
aws logs put-metric-filter --log-group-name <cloudtrail_log_group_name> --filter-name `<route_table_changes_metric>` --metric-transformations metricName= `<route_table_changes_metric>`,metricNamespace='CISBenchmark',metricValue=1 --filter-pattern '{($.eventName = CreateRoute) || ($.eventName = CreateRouteTable) || ($.eventName = ReplaceRoute) || ($.eventName = ReplaceRouteTableAssociation) || ($.eventName = DeleteRouteTable) || ($.eventName = DeleteRoute) || ($.eventName = DisassociateRouteTable) }'
Note: You can choose your own metricName and metricNamespace strings. Using the same metricNamespace for all Foundations Benchmark metrics will group them together.
- Create an SNS topic that the alarm will notify.
 
aws sns create-topic --name <sns_topic_name>
Note: you can execute this command once and then re-use the same topic for all monitoring alarms.
- Create an SNS subscription to the topic created in step 2.
 
aws sns subscribe --topic-arn <sns_topic_arn> --protocol <protocol_for_sns> --notification-endpoint <sns_subscription_endpoints>
Note: you can execute this command once and then re-use the SNS subscription for all.
- Create an alarm that is associated with the CloudWatch Logs Metric Filter created in step 1 and an SNS topic created in step 2.
 
aws cloudwatch put-metric-alarm --alarm-name `<route_table_changes_alarm>` --metric-name `<route_table_changes_metric>` --statistic Sum --period 300 --threshold 1 --comparison-operator GreaterThanOrEqualToThreshold --evaluation-periods 1 --namespace 'CISBenchmark' --alarm-actions <sns_topic_arn>
Usage
Run the control in your terminal:
powerpipe control run aws_compliance.control.cis_v150_4_13Snapshot and share results via Turbot Pipes:
powerpipe loginpowerpipe control run aws_compliance.control.cis_v150_4_13 --shareSQL
This control uses a named query:
with trails as (  select    trail.account_id,    trail.name as trail_name,    trail.is_logging,    split_part(trail.log_group_arn, ':', 7) as log_group_name  from    aws_cloudtrail_trail as trail,    jsonb_array_elements(trail.event_selectors) as se  where    trail.is_multi_region_trail is true    and trail.is_logging    and se ->> 'ReadWriteType' = 'All'    and trail.log_group_arn is not null  order by    trail_name),alarms as (  select    metric_name,    action_arn as topic_arn  from    aws_cloudwatch_alarm,    jsonb_array_elements_text(aws_cloudwatch_alarm.alarm_actions) as action_arn  order by    metric_name),topic_subscriptions as (  select    subscription_arn,    topic_arn  from    aws_sns_topic_subscription  order by    subscription_arn),metric_filters as (  select    filter.name as filter_name,    filter_pattern,    log_group_name,    metric_transformation_name  from    aws_cloudwatch_log_metric_filter as filter  where    filter.filter_pattern ~ '\s*\$\.eventName\s*=\s*CreateRoute.+\$\.eventName\s*=\s*CreateRouteTable.+\$\.eventName\s*=\s*ReplaceRoute.+\$\.eventName\s*=\s*ReplaceRouteTableAssociation.+\$\.eventName\s*=\s*DeleteRouteTable.+\$\.eventName\s*=\s*DeleteRoute.+\$\.eventName\s*=\s*DisassociateRouteTable'  order by    filter_name),filter_data as (  select    t.account_id,    t.trail_name,    f.filter_name  from    trails as t  join    metric_filters as f on f.log_group_name = t.log_group_name  join    alarms as alarm on alarm.metric_name = f.metric_transformation_name  join    topic_subscriptions as subscription on subscription.topic_arn = alarm.topic_arn)select  distinct 'arn:' || a.partition || ':::' || a.account_id as resource,  case    when f.trail_name is null then 'alarm'    else 'ok'  end as status,  case    when f.trail_name is null then 'No log metric filter and alarm exist for route table changes.'    else filter_name || ' forwards events for route table changes.'  end as reason  , a.account_idfrom  aws_account as a  left join filter_data as f on a.account_id = f.account_id;