Monitoring

Create SNS Topic and Subscription

This SNS topic and subscription will be used for all monitoring enabled in the next steps

aws sns create-topic --name monitoring-topic
aws sns subscribe \ --topic-arn <ARN_OF_TOPIC> \ --protocol email \ --notification-endpoint <admin@example.com>

<ARN_OF_TOPIC> and admin@example.com should be substituted with proper values before running the previous command. Note down the ARN of topic for future use

Ensure a log metric filter and alarm exist for unauthorized API calls

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name UnAuthorizedAPICalls \ --filter-pattern '{($.errorCode="*UnauthorizedOperation") || ($.errorCode="AccessDenied*")}' \ --metric-transformations metricName=UnAuthorizedAPICalls,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name UnAuthorizedAPICallsAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name UnAuthorizedAPICalls \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for Management Console sign-in without MFA

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name NoMFASignIn \ --filter-pattern '{($.eventName="ConsoleLogin") && ($.additionalEventData.MFAUsed !="Yes")}' \ --metric-transformations metricName=NoMFASignIn,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name NoMFASignInAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name NoMFASignIn \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for usage of "root" account

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name RootAccountUsage \ --filter-pattern '{$.userIdentity.type="Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType !="AwsServiceEvent"}' \ --metric-transformations metricName=RootAccountUsage,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name RootAccountUsageAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name RootAccountUsage \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for IAM policy changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name IAMPolicyChange \ --filter-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-transformations metricName=IAMPolicyChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name IAMPolicyChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name IAMPolicyChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for CloudTrail configuration changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name CloudTrailConfigChange \ --filter-pattern '{($.eventName=CreateTrail) || ($.eventName=UpdateTrail) || ($.eventName=DeleteTrail) || ($.eventName=StartLogging) || ($.eventName=StopLogging)}' \ --metric-transformations metricName=CloudTrailConfigChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name CloudTrailConfigChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name CloudTrailConfigChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for AWS Management Console authentication failures

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name ConsoleAuthFailure \ --filter-pattern '{($.eventName=ConsoleLogin) && ($.errorMessage="Failed authentication")}' \ --metric-transformations metricName=ConsoleAuthFailure,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name ConsoleAuthFailureAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name ConsoleAuthFailure \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name DisableOrDeleteCMK \ --filter-pattern '{($.eventSource=kms.amazonaws.com) && (($.eventName=DisableKey) || ($.eventName=ScheduleKeyDeletion))}' \ --metric-transformations metricName=DisableOrDeleteCMK,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name DisableOrDeleteCMKAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name DisableOrDeleteCMK \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for S3 bucket policy changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name S3bucketPolicyChange \ --filter-pattern '{($.eventSource=s3.amazonaws.com) && (($.eventName=PutBucketAcl) || ($.eventName=PutBucketPolicy) || ($.eventName=PutBucketCors) || ($.eventName=PutBucketLifecycle) || ($.eventName=PutBucketReplication) || ($.eventName=DeleteBucketPolicy) || ($.eventName=DeleteBucketCors) || ($.eventName=DeleteBucketLifecycle) || ($.eventName=DeleteBucketReplication))}' \ --metric-transformations metricName=S3bucketPolicyChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name S3bucketPolicyChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name S3bucketPolicyChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for AWS Config configuration changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name AWSConfigChange \ --filter-pattern '{($.eventSource=config.amazonaws.com) && (($.eventName=StopConfigurationRecorder) || ($.eventName=DeleteDeliveryChannel) || ($.eventName=PutDeliveryChannel) || ($.eventName=PutConfigurationRecorder))}' \ --metric-transformations metricName=AWSConfigChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name AWSConfigChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name AWSConfigChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for security group changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name SecurityGroupChange \ --filter-pattern '{($.eventName=AuthorizeSecurityGroupIngress) || ($.eventName=AuthorizeSecurityGroupEgress) || ($.eventName=RevokeSecurityGroupIngress) || ($.eventName=RevokeSecurityGroupEgress) || ($.eventName=CreateSecurityGroup) || ($.eventName=DeleteSecurityGroup)}' \ --metric-transformations metricName=SecurityGroupChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name SecurityGroupChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name SecurityGroupChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL)

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name NACLChange \ --filter-pattern '{($.eventName=CreateNetworkAcl) || ($.eventName=CreateNetworkAclEntry) || ($.eventName=DeleteNetworkAcl) || ($.eventName=DeleteNetworkAclEntry) || ($.eventName=ReplaceNetworkAclEntry) || ($.eventName=ReplaceNetworkAclAssociation)}' \ --metric-transformations metricName=NACLChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name NACLChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name NACLChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for changes to network gateways

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name NetworkGatewayChange \ --filter-pattern '{($.eventName=CreateCustomerGateway) || ($.eventName=DeleteCustomerGateway) || ($.eventName=AttachInternetGateway) || ($.eventName=CreateInternetGateway) || ($.eventName=DeleteInternetGateway) || ($.eventName=DetachInternetGateway)}' \ --metric-transformations metricName=NetworkGatewayChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name NetworkGatewayChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name NetworkGatewayChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for route table changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name RouteTableChange \ --filter-pattern '{($.eventName=CreateRoute) || ($.eventName=CreateRouteTable) || ($.eventName=ReplaceRoute) || ($.eventName=ReplaceRouteTableAssociation) || ($.eventName=DeleteRouteTable) || ($.eventName=DeleteRoute) || ($.eventName=DisassociateRouteTable)}' \ --metric-transformations metricName=RouteTableChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name RouteTableChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name RouteTableChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>

Ensure a log metric filter and alarm exist for VPC changes

Create Metric Filter

aws logs put-metric-filter \ --log-group-name <CloudTrail_Log_Group_Name> \ --filter-name VPCChange \ --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=VPCChange,metricNamespace=LogMetrics,metricValue=1

Create Alarm using above Metric

aws cloudwatch put-metric-alarm \ --alarm-name VPCChangeAlarm \ --comparison-operator GreaterThanOrEqualToThreshold \ --evaluation-periods 1 \ --metric-name VPCChange \ --namespace LogMetrics \ --period 300 \ --statistic Sum \ --threshold 1 \ --alarm-actions <ARN_OF_TOPIC>