├── .github └── CODEOWNERS ├── CIS-alarms-cfn.yml ├── LICENSE └── README.md /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Each line is a file pattern followed by one or more owners. 2 | 3 | # These owners will be the default owners for everything in 4 | # the repo. Unless a later match takes precedence, members of 5 | # @rewindio/codeowners will be requested for review when someone 6 | # opens a pull request. 7 | * @rewindio/devops 8 | -------------------------------------------------------------------------------- /CIS-alarms-cfn.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AWSTemplateFormatVersion: 2010-09-09 3 | Description: CIS AWS Foundations Benchmark Metric Alarms 4 | Parameters: 5 | AlarmNotificationTopicARN: 6 | Description: Replace Default value with the ARN for your SNS alarm 7 | Default: 'arn:aws:sns:aws-region:your-account#:your-CIS-Alarms' 8 | Type: String 9 | CloudtrailLogGroupName: 10 | Description: Replace Default value with the name (not ARN) for your CloudTrail's CloudWatch Log Group 11 | Default: 'Example-Cloudwatch-For-Trail-LogGroup' 12 | Type: String 13 | Resources: 14 | #=============================================================================================================================== 15 | # MetricFilter and CloudWatch Alarm Section 16 | #=============================================================================================================================== 17 | 18 | # ------------------------------------------------------------------------------------------------------------------------------------ 19 | # CIS AWS Foundations Benchmark - 3.1 Ensure a log metric filter and alarm exist for unauthorized API calls (Scored) 20 | # ------------------------------------------------------------------------------------------------------------------------------------ 21 | UnauthorizedApiCallsAlarm: 22 | Type: AWS::CloudWatch::Alarm 23 | Properties: 24 | AlarmName: CIS-Unauthorized Activity Attempt 25 | AlarmDescription: Alarm if Multiple unauthorized actions or logins attempted 26 | MetricName: UnauthorizedAttemptCount 27 | Namespace: CloudTrailMetrics 28 | Statistic: Sum 29 | Period: 300 30 | EvaluationPeriods: 1 31 | Threshold: 1 32 | TreatMissingData: notBreaching 33 | AlarmActions: 34 | - !Ref AlarmNotificationTopicARN 35 | ComparisonOperator: GreaterThanOrEqualToThreshold 36 | UnauthorizedApiCallsFilter: 37 | Type: AWS::Logs::MetricFilter 38 | Properties: 39 | LogGroupName: !Ref CloudtrailLogGroupName 40 | FilterPattern: |- 41 | { 42 | ($.errorCode = "*UnauthorizedOperation") || 43 | ($.errorCode = "AccessDenied*") 44 | } 45 | MetricTransformations: 46 | - MetricValue: '1' 47 | MetricNamespace: CloudTrailMetrics 48 | MetricName: UnauthorizedAttemptCount 49 | UnauthorizedApiCallsQuery: 50 | Type: AWS::Logs::QueryDefinition 51 | Properties: 52 | Name: CIS-Alarms/CIS-Unauthorized Activity Attempt 53 | LogGroupNames: 54 | - !Ref CloudtrailLogGroupName 55 | QueryString: |- 56 | fields @timestamp, @message | 57 | sort @timestamp desc | 58 | filter errorCode == '*UnauthorizedOperation' or errorCode == 'AccessDenied*' 59 | 60 | # ------------------------------------------------------------------------------------------------------------------------------------ 61 | # CIS AWS Foundations Benchmark - 3.2 Ensure a log metric filter and alarm exist for Management Console sign-in without MFA (Scored) 62 | # ------------------------------------------------------------------------------------------------------------------------------------ 63 | NoMfaConsoleLoginsAlarm: 64 | Type: AWS::CloudWatch::Alarm 65 | Properties: 66 | AlarmName: CIS-Console Signin Without MFA 67 | AlarmDescription: Alarm if there is a Management Console sign-in without MFA 68 | MetricName: ConsoleSigninWithoutMFA 69 | Namespace: CloudTrailMetrics 70 | Statistic: Sum 71 | Period: 300 72 | EvaluationPeriods: 1 73 | Threshold: 1 74 | TreatMissingData: notBreaching 75 | AlarmActions: 76 | - !Ref AlarmNotificationTopicARN 77 | ComparisonOperator: GreaterThanOrEqualToThreshold 78 | NoMfaConsoleLoginsFilter: 79 | Type: AWS::Logs::MetricFilter 80 | Properties: 81 | LogGroupName: !Ref CloudtrailLogGroupName 82 | FilterPattern: |- 83 | { 84 | ($.eventName = "ConsoleLogin") && 85 | ($.additionalEventData.MFAUsed != "Yes") 86 | } 87 | MetricTransformations: 88 | - MetricValue: '1' 89 | MetricNamespace: CloudTrailMetrics 90 | MetricName: ConsoleSigninWithoutMFA 91 | NoMfaConsoleLoginsQuery: 92 | Type: AWS::Logs::QueryDefinition 93 | Properties: 94 | Name: CIS-Alarms/CIS-Console Signin Without MFA 95 | LogGroupNames: 96 | - !Ref CloudtrailLogGroupName 97 | QueryString: |- 98 | fields @timestamp, @message | 99 | sort @timestamp desc | 100 | filter eventName == 'ConsoleLogin' and responseElements.ConsoleLogin == 'Success' and additionalEventData.MFAUsed != 'Yes' 101 | 102 | # ------------------------------------------------------------------------------------------------------------------------------------ 103 | # CIS AWS Foundations Benchmark - 1.1 Avoid the use of the "root" account (Scored) 104 | # CIS AWS Foundations Benchmark - 3.3 Ensure a log metric filter and alarm exist for usage of "root" account (Scored) 105 | # ------------------------------------------------------------------------------------------------------------------------------------ 106 | RootAccountLoginsAlarm: 107 | Type: AWS::CloudWatch::Alarm 108 | DependsOn: 109 | - NoMfaConsoleLoginsAlarm 110 | Properties: 111 | AlarmName: CIS-Root Activity 112 | AlarmDescription: Alarm if a 'root' user uses the account 113 | MetricName: RootUserEventCount 114 | Namespace: CloudTrailMetrics 115 | Statistic: Sum 116 | Period: 300 117 | EvaluationPeriods: 1 118 | Threshold: 1 119 | TreatMissingData: notBreaching 120 | AlarmActions: 121 | - !Ref AlarmNotificationTopicARN 122 | ComparisonOperator: GreaterThanOrEqualToThreshold 123 | RootAccountLoginsFilter: 124 | Type: AWS::Logs::MetricFilter 125 | Properties: 126 | LogGroupName: !Ref CloudtrailLogGroupName 127 | FilterPattern: |- 128 | { 129 | $.userIdentity.type = "Root" && 130 | $.userIdentity.invokedBy NOT EXISTS && 131 | $.eventType != "AwsServiceEvent" 132 | } 133 | MetricTransformations: 134 | - MetricValue: '1' 135 | MetricNamespace: CloudTrailMetrics 136 | MetricName: RootUserEventCount 137 | RootAccountLoginsQuery: 138 | Type: AWS::Logs::QueryDefinition 139 | Properties: 140 | Name: CIS-Alarms/CIS-Root Activity 141 | LogGroupNames: 142 | - !Ref CloudtrailLogGroupName 143 | QueryString: |- 144 | fields @timestamp, @message | 145 | sort @timestamp desc | 146 | filter userIdentity.type == 'Root' and eventType != 'AwsServiceEvent' 147 | 148 | # -------------------------------------------------------------------------------------------------------------------------------------------- 149 | # CIS AWS Foundations Benchmark - 3.4 Ensure a log metric filter and alarm exist for IAM policy changes (Scored) 150 | # -------------------------------------------------------------------------------------------------------------------------------------------- 151 | IAMPolicyChangesAlarm: 152 | Type: AWS::CloudWatch::Alarm 153 | Properties: 154 | AlarmName: CIS-IAM Policy Changes 155 | AlarmDescription: Alarm if an IAM policy changes 156 | MetricName: IAMPolicyChangeEventCount 157 | Namespace: CloudTrailMetrics 158 | Statistic: Sum 159 | Period: 300 160 | EvaluationPeriods: 1 161 | Threshold: 1 162 | TreatMissingData: notBreaching 163 | AlarmActions: 164 | - !Ref AlarmNotificationTopicARN 165 | ComparisonOperator: GreaterThanOrEqualToThreshold 166 | IAMPolicyChangesFilter: 167 | Type: AWS::Logs::MetricFilter 168 | Properties: 169 | LogGroupName: !Ref CloudtrailLogGroupName 170 | FilterPattern: |- 171 | { 172 | ($.eventName=DeleteGroupPolicy) || 173 | ($.eventName=DeleteRolePolicy) || 174 | ($.eventName=DeleteUserPolicy) || 175 | ($.eventName=PutGroupPolicy) || 176 | ($.eventName=PutRolePolicy) || 177 | ($.eventName=PutUserPolicy) || 178 | ($.eventName=CreatePolicy) || 179 | ($.eventName=DeletePolicy) || 180 | ($.eventName=CreatePolicyVersion) || 181 | ($.eventName=DeletePolicyVersion) || 182 | ($.eventName=AttachRolePolicy) || 183 | ($.eventName=DetachRolePolicy) || 184 | ($.eventName=AttachUserPolicy) || 185 | ($.eventName=DetachUserPolicy) || 186 | ($.eventName=AttachGroupPolicy) || 187 | ($.eventName=DetachGroupPolicy) 188 | } 189 | MetricTransformations: 190 | - MetricValue: '1' 191 | MetricNamespace: CloudTrailMetrics 192 | MetricName: IAMPolicyChangeEventCount 193 | IAMPolicyChangesQuery: 194 | Type: AWS::Logs::QueryDefinition 195 | Properties: 196 | Name: CIS-Alarms/CIS-IAM Policy Changes 197 | LogGroupNames: 198 | - !Ref CloudtrailLogGroupName 199 | QueryString: |- 200 | fields @timestamp, @message | 201 | sort @timestamp desc | 202 | filter eventName in ['AttachGroupPolicy', 'AttachRolePolicy', 'AttachUserPolicy', 'CreatePolicy', 'CreatePolicyVersion', 'DeleteGroupPolicy', 'DeletePolicy', 'DeletePolicyVersion', 'DeleteRolePolicy', 'DeleteUserPolicy', 'DetachGroupPolicy', 'DetachRolePolicy', 'DetachUserPolicy', 'PutGroupPolicy', 'PutRolePolicy', 'PutUserPolicy'] 203 | 204 | # -------------------------------------------------------------------------------------------------------------------------------------------- 205 | # CIS AWS Foundations Benchmark - 3.5 Ensure a log metric filter and alarm exist for CloudTrail configuration changes (Scored) 206 | # -------------------------------------------------------------------------------------------------------------------------------------------- 207 | CloudtrailConfigChangesAlarm: 208 | Type: AWS::CloudWatch::Alarm 209 | Properties: 210 | AlarmName: CIS-Cloudtrail Config Changes 211 | AlarmDescription: Alarm if the configuration for Cloudtrail changes 212 | MetricName: CloudtrailConfigChangeEventCount 213 | Namespace: CloudTrailMetrics 214 | Statistic: Sum 215 | Period: 300 216 | EvaluationPeriods: 1 217 | Threshold: 1 218 | TreatMissingData: notBreaching 219 | AlarmActions: 220 | - !Ref AlarmNotificationTopicARN 221 | ComparisonOperator: GreaterThanOrEqualToThreshold 222 | CloudtrailConfigChangesFilter: 223 | Type: AWS::Logs::MetricFilter 224 | Properties: 225 | LogGroupName: !Ref CloudtrailLogGroupName 226 | FilterPattern: |- 227 | { 228 | ($.eventName = CreateTrail) || 229 | ($.eventName = UpdateTrail) || 230 | ($.eventName = DeleteTrail) || 231 | ($.eventName = StartLogging) || 232 | ($.eventName = StopLogging) 233 | } 234 | MetricTransformations: 235 | - MetricValue: '1' 236 | MetricNamespace: CloudTrailMetrics 237 | MetricName: CloudtrailConfigChangeEventCount 238 | CloudtrailConfigChangesQuery: 239 | Type: AWS::Logs::QueryDefinition 240 | Properties: 241 | Name: CIS-Alarms/CIS-Cloudtrail Config Changes 242 | LogGroupNames: 243 | - !Ref CloudtrailLogGroupName 244 | QueryString: |- 245 | fields @timestamp, @message | 246 | sort @timestamp desc | 247 | filter eventName in ['CreateTrail', 'DeleteTrail', 'StartLogging', 'StopLogging', 'UpdateTrail'] 248 | 249 | # -------------------------------------------------------------------------------------------------------------------------------------------- 250 | # CIS AWS Foundations Benchmark - 3.6 Ensure a log metric filter and alarm exist for AWS Management Console authentication failures (Scored) 251 | # -------------------------------------------------------------------------------------------------------------------------------------------- 252 | FailedConsoleLoginsAlarm: 253 | Type: AWS::CloudWatch::Alarm 254 | DependsOn: 255 | - RootAccountLoginsAlarm 256 | Properties: 257 | AlarmName: CIS-Console Login Failures 258 | AlarmDescription: Alarm if there are AWS Management Console authentication failures 259 | MetricName: ConsoleLoginFailures 260 | Namespace: CloudTrailMetrics 261 | Statistic: Sum 262 | Period: 300 263 | EvaluationPeriods: 1 264 | Threshold: 1 265 | TreatMissingData: notBreaching 266 | AlarmActions: 267 | - !Ref AlarmNotificationTopicARN 268 | ComparisonOperator: GreaterThanOrEqualToThreshold 269 | FailedConsoleLoginsFilter: 270 | Type: AWS::Logs::MetricFilter 271 | Properties: 272 | LogGroupName: !Ref CloudtrailLogGroupName 273 | FilterPattern: |- 274 | { 275 | ($.eventName = ConsoleLogin) && 276 | ($.errorMessage = "Failed authentication") 277 | } 278 | MetricTransformations: 279 | - MetricValue: '1' 280 | MetricNamespace: CloudTrailMetrics 281 | MetricName: ConsoleLoginFailures 282 | FailedConsoleLoginsQuery: 283 | Type: AWS::Logs::QueryDefinition 284 | Properties: 285 | Name: CIS-Alarms/CIS-Console Login Failures 286 | LogGroupNames: 287 | - !Ref CloudtrailLogGroupName 288 | QueryString: |- 289 | fields @timestamp, @message | 290 | sort @timestamp desc | 291 | filter eventName == 'ConsoleLogin' and errorMessage == 'Failed authentication' 292 | 293 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 294 | # CIS AWS Foundations Benchmark - 3.7 Ensure a log metric filter and alarm exist for disabling or scheduled deletion of customer created CMKs (Scored) 295 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 296 | DisabledOrDeletedCmksAlarm: 297 | Type: AWS::CloudWatch::Alarm 298 | DependsOn: 299 | - FailedConsoleLoginsAlarm 300 | Properties: 301 | AlarmName: CIS-KMS Key Disabled or Scheduled for Deletion 302 | AlarmDescription: Alarm if customer created CMKs get disabled or scheduled for 303 | deletion 304 | MetricName: KMSCustomerKeyDeletion 305 | Namespace: CloudTrailMetrics 306 | Statistic: Sum 307 | Period: 60 308 | EvaluationPeriods: 1 309 | Threshold: 1 310 | TreatMissingData: notBreaching 311 | AlarmActions: 312 | - !Ref AlarmNotificationTopicARN 313 | ComparisonOperator: GreaterThanOrEqualToThreshold 314 | DisabledOrDeletedCmksFilter: 315 | Type: AWS::Logs::MetricFilter 316 | Properties: 317 | LogGroupName: !Ref CloudtrailLogGroupName 318 | FilterPattern: |- 319 | { 320 | ($.eventSource = kms.amazonaws.com) && 321 | (($.eventName=DisableKey) || ($.eventName=ScheduleKeyDeletion)) 322 | } 323 | MetricTransformations: 324 | - MetricValue: '1' 325 | MetricNamespace: CloudTrailMetrics 326 | MetricName: KMSCustomerKeyDeletion 327 | DisabledOrDeletedCmksQuery: 328 | Type: AWS::Logs::QueryDefinition 329 | Properties: 330 | Name: CIS-Alarms/CIS-KMS Key Disabled or Scheduled for Deletion 331 | LogGroupNames: 332 | - !Ref CloudtrailLogGroupName 333 | QueryString: |- 334 | fields @timestamp, @message | 335 | sort @timestamp desc | 336 | filter eventSource == 'kms.amazonaws.com' and eventName in ['DisableKey', 'ScheduleKeyDeletion'] 337 | 338 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 339 | # CIS AWS Foundations Benchmark - 3.8 Ensure a log metric filter and alarm exist for S3 bucket policy changes (Scored) 340 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 341 | S3BucketPolicyChangeAlarm: 342 | Type: AWS::CloudWatch::Alarm 343 | Properties: 344 | AlarmName: CIS-S3 Bucket Policy Changed 345 | AlarmDescription: Alarm if any S3 bucket policies are changed 346 | MetricName: S3BucketPolicyChanges 347 | Namespace: CloudTrailMetrics 348 | Statistic: Sum 349 | Period: 300 350 | EvaluationPeriods: 1 351 | Threshold: 1 352 | TreatMissingData: notBreaching 353 | AlarmActions: 354 | - !Ref AlarmNotificationTopicARN 355 | ComparisonOperator: GreaterThanOrEqualToThreshold 356 | S3BucketPolicyChangeFilter: 357 | Type: AWS::Logs::MetricFilter 358 | Properties: 359 | LogGroupName: !Ref CloudtrailLogGroupName 360 | FilterPattern: |- 361 | { 362 | ($.eventSource = s3.amazonaws.com) && 363 | (($.eventName = PutBucketAcl) || 364 | ($.eventName = PutBucketPolicy) || 365 | ($.eventName = PutBucketCors) || 366 | ($.eventName = PutBucketLifecycle) || 367 | ($.eventName = PutBucketReplication) || 368 | ($.eventName = DeleteBucketPolicy) || 369 | ($.eventName = DeleteBucketCors) || 370 | ($.eventName = DeleteBucketLifecycle) || 371 | ($.eventName = DeleteBucketReplication)) 372 | } 373 | MetricTransformations: 374 | - MetricValue: '1' 375 | MetricNamespace: CloudTrailMetrics 376 | MetricName: S3BucketPolicyChanges 377 | S3BucketPolicyChangeQuery: 378 | Type: AWS::Logs::QueryDefinition 379 | Properties: 380 | Name: CIS-Alarms/CIS-S3 Bucket Policy Changed 381 | LogGroupNames: 382 | - !Ref CloudtrailLogGroupName 383 | QueryString: |- 384 | fields @timestamp, @message | 385 | sort @timestamp desc | 386 | filter eventSource = 's3.amazonaws.com' and eventName in ['DeleteBucketCors', 'DeleteBucketLifecycle', 'DeleteBucketPolicy', 'DeleteBucketReplication', 'PutBucketAcl', 'PutBucketCors', 'PutBucketLifecycle', 'PutBucketPolicy', 'PutBucketReplication'] 387 | 388 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 389 | # CIS AWS Foundations Benchmark - 3.9 Ensure a log metric filter and alarm exist for AWS Config configuration changes (Scored) 390 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 391 | AWSConfigConfigurationChangeAlarm: 392 | Type: AWS::CloudWatch::Alarm 393 | Properties: 394 | AlarmName: CIS-AWS Config Configuration has changed 395 | AlarmDescription: Alarm if the configuration for AWS Config changes 396 | MetricName: AWSConfigConfigurationChanges 397 | Namespace: CloudTrailMetrics 398 | Statistic: Sum 399 | Period: 300 400 | EvaluationPeriods: 1 401 | Threshold: 1 402 | TreatMissingData: notBreaching 403 | AlarmActions: 404 | - !Ref AlarmNotificationTopicARN 405 | ComparisonOperator: GreaterThanOrEqualToThreshold 406 | AWSConfigConfigurationChangeFilter: 407 | Type: AWS::Logs::MetricFilter 408 | Properties: 409 | LogGroupName: !Ref CloudtrailLogGroupName 410 | FilterPattern: |- 411 | { 412 | ($.eventSource = config.amazonaws.com) && 413 | (($.eventName=StopConfigurationRecorder)|| 414 | ($.eventName=DeleteDeliveryChannel)|| 415 | ($.eventName=PutDeliveryChannel)|| 416 | ($.eventName=PutConfigurationRecorder)) 417 | } 418 | MetricTransformations: 419 | - MetricValue: '1' 420 | MetricNamespace: CloudTrailMetrics 421 | MetricName: AWSConfigConfigurationChanges 422 | AWSConfigConfigurationChangeQuery: 423 | Type: AWS::Logs::QueryDefinition 424 | Properties: 425 | Name: CIS-Alarms/CIS-AWS Config Configuration has changed 426 | LogGroupNames: 427 | - !Ref CloudtrailLogGroupName 428 | QueryString: |- 429 | fields @timestamp, @message | 430 | sort @timestamp desc | 431 | filter eventSource = 'config.amazonaws.com' and eventName in ['DeleteDeliveryChannel', 'StopConfigurationRecorder', 'PutConfigurationRecorder', 'PutDeliveryChannel'] 432 | 433 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 434 | # CIS AWS Foundations Benchmark - 3.10 Ensure a log metric filter and alarm exist for security group changes (Scored) 435 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 436 | SecurityGroupChangeAlarm: 437 | Type: AWS::CloudWatch::Alarm 438 | Properties: 439 | AlarmName: CIS-Security Groups Have Changed 440 | AlarmDescription: Alarm if there are any changes to security groups 441 | MetricName: SecurityGroupChanges 442 | Namespace: CloudTrailMetrics 443 | Statistic: Sum 444 | Period: 300 445 | EvaluationPeriods: 1 446 | Threshold: 1 447 | TreatMissingData: notBreaching 448 | AlarmActions: 449 | - !Ref AlarmNotificationTopicARN 450 | ComparisonOperator: GreaterThanOrEqualToThreshold 451 | SecurityGroupChangeFilter: 452 | Type: AWS::Logs::MetricFilter 453 | Properties: 454 | LogGroupName: !Ref CloudtrailLogGroupName 455 | FilterPattern: |- 456 | { 457 | ($.eventName = AuthorizeSecurityGroupIngress) || 458 | ($.eventName = AuthorizeSecurityGroupEgress) || 459 | ($.eventName = RevokeSecurityGroupIngress) || 460 | ($.eventName = RevokeSecurityGroupEgress) || 461 | ($.eventName = CreateSecurityGroup) || 462 | ($.eventName = DeleteSecurityGroup) 463 | } 464 | MetricTransformations: 465 | - MetricValue: '1' 466 | MetricNamespace: CloudTrailMetrics 467 | MetricName: SecurityGroupChanges 468 | SecurityGroupChangeQuery: 469 | Type: AWS::Logs::QueryDefinition 470 | Properties: 471 | Name: CIS-Alarms/CIS-Security Groups Have Changed 472 | LogGroupNames: 473 | - !Ref CloudtrailLogGroupName 474 | QueryString: |- 475 | fields @timestamp, @message | 476 | sort @timestamp desc | 477 | filter eventName in ['AuthorizeSecurityGroupIngress', 'AuthorizeSecurityGroupEgress', 'CreateSecurityGroup', 'DeleteSecurityGroup', 'RevokeSecurityGroupIngress', 'RevokeSecurityGroupEgress'] 478 | 479 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 480 | # CIS AWS Foundations Benchmark - 3.11 Ensure a log metric filter and alarm exist for changes to Network Access Control Lists (NACL) (Scored) 481 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 482 | NACLChangeAlarm: 483 | Type: AWS::CloudWatch::Alarm 484 | Properties: 485 | AlarmName: CIS-NACLs Have Changed 486 | AlarmDescription: Alarm if there are any changes to Network ACLs (NACLs) 487 | MetricName: NACLChanges 488 | Namespace: CloudTrailMetrics 489 | Statistic: Sum 490 | Period: 300 491 | EvaluationPeriods: 1 492 | Threshold: 1 493 | TreatMissingData: notBreaching 494 | AlarmActions: 495 | - !Ref AlarmNotificationTopicARN 496 | ComparisonOperator: GreaterThanOrEqualToThreshold 497 | NACLChangeFilter: 498 | Type: AWS::Logs::MetricFilter 499 | Properties: 500 | LogGroupName: !Ref CloudtrailLogGroupName 501 | FilterPattern: |- 502 | { 503 | ($.eventName = CreateNetworkAcl) || 504 | ($.eventName = CreateNetworkAclEntry) || 505 | ($.eventName = DeleteNetworkAcl) || 506 | ($.eventName = DeleteNetworkAclEntry) || 507 | ($.eventName = ReplaceNetworkAclEntry) || 508 | ($.eventName = ReplaceNetworkAclAssociation) 509 | } 510 | MetricTransformations: 511 | - MetricValue: '1' 512 | MetricNamespace: CloudTrailMetrics 513 | MetricName: NACLChanges 514 | NACLChangeQuery: 515 | Type: AWS::Logs::QueryDefinition 516 | Properties: 517 | Name: CIS-Alarms/CIS-NACLs Have Changed 518 | LogGroupNames: 519 | - !Ref CloudtrailLogGroupName 520 | QueryString: |- 521 | fields @timestamp, @message | 522 | sort @timestamp desc | 523 | filter eventName in ['CreateNetworkAcl', 'CreateNetworkAclEntry', 'DeleteNetworkAcl', 'DeleteNetworkAclEntry', 'ReplaceNetworkAclEntry', 'ReplaceNetworkAclAssociation'] 524 | 525 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 526 | # CIS AWS Foundations Benchmark - 3.12 Ensure a log metric filter and alarm exist for changes to network gateways (Scored) 527 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 528 | NetworkGatewayChangeAlarm: 529 | Type: AWS::CloudWatch::Alarm 530 | Properties: 531 | AlarmName: CIS-Network Gateways Have Changed 532 | AlarmDescription: Alarm if there are any changes to network gateways 533 | MetricName: NetworkGatewayChanges 534 | Namespace: CloudTrailMetrics 535 | Statistic: Sum 536 | Period: 300 537 | EvaluationPeriods: 1 538 | Threshold: 1 539 | TreatMissingData: notBreaching 540 | AlarmActions: 541 | - !Ref AlarmNotificationTopicARN 542 | ComparisonOperator: GreaterThanOrEqualToThreshold 543 | NetworkGatewayChangeFilter: 544 | Type: AWS::Logs::MetricFilter 545 | Properties: 546 | LogGroupName: !Ref CloudtrailLogGroupName 547 | FilterPattern: |- 548 | { 549 | ($.eventName = CreateCustomerGateway) || 550 | ($.eventName = DeleteCustomerGateway) || 551 | ($.eventName = AttachInternetGateway) || 552 | ($.eventName = CreateInternetGateway) || 553 | ($.eventName = DeleteInternetGateway) || 554 | ($.eventName = DetachInternetGateway) 555 | } 556 | MetricTransformations: 557 | - MetricValue: '1' 558 | MetricNamespace: CloudTrailMetrics 559 | MetricName: NetworkGatewayChanges 560 | NetworkGatewayChangeQuery: 561 | Type: AWS::Logs::QueryDefinition 562 | Properties: 563 | Name: CIS-Alarms/CIS-Network Gateways Have Changed 564 | LogGroupNames: 565 | - !Ref CloudtrailLogGroupName 566 | QueryString: |- 567 | fields @timestamp, @message | 568 | sort @timestamp desc | 569 | filter eventName in ['AttachInternetGateway', 'CreateCustomerGateway', 'CreateInternetGateway', 'DeleteCustomerGateway', 'DeleteInternetGateway', 'DetachInternetGateway'] 570 | 571 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 572 | # CIS AWS Foundations Benchmark - 3.13 Ensure a log metric filter and alarm exist for route table changes (Scored) 573 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 574 | RouteTableChangeAlarm: 575 | Type: AWS::CloudWatch::Alarm 576 | Properties: 577 | AlarmName: CIS-Route Tables Have Changed 578 | AlarmDescription: Alarm if there are any changes to route tables 579 | MetricName: RouteTableChanges 580 | Namespace: CloudTrailMetrics 581 | Statistic: Sum 582 | Period: 300 583 | EvaluationPeriods: 1 584 | Threshold: 1 585 | TreatMissingData: notBreaching 586 | AlarmActions: 587 | - !Ref AlarmNotificationTopicARN 588 | ComparisonOperator: GreaterThanOrEqualToThreshold 589 | RouteTableChangeFilter: 590 | Type: AWS::Logs::MetricFilter 591 | Properties: 592 | LogGroupName: !Ref CloudtrailLogGroupName 593 | FilterPattern: |- 594 | { 595 | ($.eventName = CreateRoute) || 596 | ($.eventName = CreateRouteTable) || 597 | ($.eventName = ReplaceRoute) || 598 | ($.eventName = ReplaceRouteTableAssociation) || 599 | ($.eventName = DeleteRouteTable) || 600 | ($.eventName = DeleteRoute) || 601 | ($.eventName = DisassociateRouteTable) 602 | } 603 | MetricTransformations: 604 | - MetricValue: '1' 605 | MetricNamespace: CloudTrailMetrics 606 | MetricName: RouteTableChanges 607 | RouteTableChangeQuery: 608 | Type: AWS::Logs::QueryDefinition 609 | Properties: 610 | Name: CIS-Alarms/CIS-Route Tables Have Changed 611 | LogGroupNames: 612 | - !Ref CloudtrailLogGroupName 613 | QueryString: |- 614 | fields @timestamp, @message | 615 | sort @timestamp desc | 616 | filter eventName in ['CreateRoute', 'CreateRouteTable', 'DeleteRoute', 'DeleteRouteTable', 'DisassociateRouteTable', 'ReplaceRoute', 'ReplaceRouteTableAssociation'] 617 | 618 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 619 | # CIS AWS Foundations Benchmark - 3.14 Ensure a log metric filter and alarm exist for VPC changes (Scored) 620 | # ------------------------------------------------------------------------------------------------------------------------------------------------------- 621 | VPCChangeAlarm: 622 | Type: AWS::CloudWatch::Alarm 623 | Properties: 624 | AlarmName: CIS-VPC Has Changed 625 | AlarmDescription: Alarm if there are any changes to any VPCs 626 | MetricName: VPCChanges 627 | Namespace: CloudTrailMetrics 628 | Statistic: Sum 629 | Period: 300 630 | EvaluationPeriods: 1 631 | Threshold: 1 632 | TreatMissingData: notBreaching 633 | AlarmActions: 634 | - !Ref AlarmNotificationTopicARN 635 | ComparisonOperator: GreaterThanOrEqualToThreshold 636 | VPCChangeFilter: 637 | Type: AWS::Logs::MetricFilter 638 | Properties: 639 | LogGroupName: !Ref CloudtrailLogGroupName 640 | FilterPattern: |- 641 | { 642 | ($.eventName = CreateVpc) || 643 | ($.eventName = DeleteVpc) || 644 | ($.eventName = ModifyVpcAttribute) || 645 | ($.eventName = AcceptVpcPeeringConnection) || 646 | ($.eventName = CreateVpcPeeringConnection) || 647 | ($.eventName = DeleteVpcPeeringConnection) || 648 | ($.eventName = RejectVpcPeeringConnection) || 649 | ($.eventName = AttachClassicLinkVpc) || 650 | ($.eventName = DetachClassicLinkVpc) || 651 | ($.eventName = DisableVpcClassicLink) || 652 | ($.eventName = EnableVpcClassicLink) 653 | } 654 | MetricTransformations: 655 | - MetricValue: '1' 656 | MetricNamespace: CloudTrailMetrics 657 | MetricName: VPCChanges 658 | VPCChangeQuery: 659 | Type: AWS::Logs::QueryDefinition 660 | Properties: 661 | Name: CIS-Alarms/CIS-VPC Has Changed 662 | LogGroupNames: 663 | - !Ref CloudtrailLogGroupName 664 | QueryString: |- 665 | fields @timestamp, @message | 666 | sort @timestamp desc | 667 | filter eventName in ['AcceptVpcPeeringConnection', 'AttachClassicLinkVpc', 'CreateVpc', 'CreateVpcPeeringConnection', 'DeleteVpc', 'DeleteVpcPeeringConnection', 'DetachClassicLinkVpc', 'DisableVpcClassicLink', 'EnableVpcClassicLink', 'ModifyVpcAttribute', 'RejectVpcPeeringConnection'] 668 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Rewind 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-security-hub-CIS-metrics 2 | 3 | This repo contains a cloudformation template which will create all of the needed log filters, metrics and alarms to conform with the CIS framework used by AWS Security hub. 4 | 5 | I've packaged these up in Cloudformation and based them on the [AWS quickstart example](https://github.com/aws-quickstart/quickstart-compliance-cis-benchmark/blob/master/templates/cis-benchmark.template). It should be noted however that using the AWS quickstart will not work for Security hub because the metric filters do not exactly match that which is documented in the CIS document. Security hub needs an exact match to flag a standard as being compliant. 6 | 7 | # Using 8 | * Configure Cloudtrail to send logs to a Cloudwatch log group as discussed in the Security Hub documentation 9 | * Create a new SNS topic to send your alerts to. Subscribe either your email or use our [cloudwatch slack notifier](https://github.com/rewindio/aws-cloudwatch-slack-notifier) 10 | * Create a new Cloudformation stack using the template in this repo. You'll be prompted for the SNS Topic ARN and the name of the Cloudwatch logs group that Cloudtrail is logging to (ie. /aws/cloudtrail) 11 | 12 | That should be it. Note that security hub only checks for compliance with CIS standards every 12 hours so you will need to wait until the next check to make sure your new metric filters and alarms are detected correctly by Security Hub. --------------------------------------------------------------------------------