From e3cfa599aad7d4bcda431a5e525da84e262ab575 Mon Sep 17 00:00:00 2001 From: jack1902 <39212456+jack1902@users.noreply.github.com> Date: Thu, 20 Feb 2020 14:02:16 +0000 Subject: [PATCH] [rules] Added AWS Config Compliance and Remediation Rules * Aws prefix added to relevant matchers Signed-off-by: jack1902 <39212456+jack1902@users.noreply.github.com> --- .../cloudtrail/cloudtrail_aws_config.py | 47 +++++ rules/community/guardduty/guard_duty_all.py | 4 +- rules/matchers/matchers.py | 37 +++- .../cloudtrail/cloudtrail_aws_config.json | 199 ++++++++++++++++++ 4 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 rules/community/cloudtrail/cloudtrail_aws_config.py create mode 100644 tests/integration/rules/cloudtrail/cloudtrail_aws_config.json diff --git a/rules/community/cloudtrail/cloudtrail_aws_config.py b/rules/community/cloudtrail/cloudtrail_aws_config.py new file mode 100644 index 000000000..3103cf687 --- /dev/null +++ b/rules/community/cloudtrail/cloudtrail_aws_config.py @@ -0,0 +1,47 @@ +"""Alert on AWS Config""" +from rules.matchers.matchers import AwsConfigMatcher +from streamalert.shared.rule import rule + + +# Populate this list to alert on specific Config Rules, otherwise all rules will be in-scope +# Also consider the use of Lookup-Tables +RULES_TO_ALERT_ON = [] + + +@rule(logs=["cloudtrail:events"], matchers=[AwsConfigMatcher.is_config_compliance]) +def config_compliance(record): + """ + author: jack (jack1902) + description: Alert on AWS Config Complaince Change events of NON_COMPLIANT + testing: From the Config page (https://console.aws.amazon.com/config/home) + ensure recording is turned on. And you have a basic rule you can + trigger as compliant or non-compliant. + """ + + non_compliance_present = any( + evaluation["complianceType"] == "NON_COMPLIANT" + for evaluation in record["requestParameters"]["evaluations"] + ) + + if RULES_TO_ALERT_ON: + # Alert on specific rule names. Useful when some Config Rules are just TOO noisy. + rule_name = record["additionalEventData"]["configRuleName"] + result = rule_name in RULES_TO_ALERT_ON and non_compliance_present + else: + # Alert on ALL config rules regardless of their name + result = non_compliance_present + + return result + + +@rule(logs=["cloudtrail:events"], matchers=[AwsConfigMatcher.is_auto_remediation]) +def config_auto_remediation(_): + """ + author: jack (jack1902) + description: Alert on AWS Config Auto Remediation + testing: From the Config page (https://console.aws.amazon.com/config/home) + ensure recording is turned on. And you have a basic rule you can + trigger as compliant or non-compliant. Then trigger the remediation + either manually or have it done automatically. + """ + return True diff --git a/rules/community/guardduty/guard_duty_all.py b/rules/community/guardduty/guard_duty_all.py index f30702f1f..4f2de6d8b 100644 --- a/rules/community/guardduty/guard_duty_all.py +++ b/rules/community/guardduty/guard_duty_all.py @@ -1,9 +1,9 @@ """Alert on GuardDuty""" -from rules.matchers.matchers import GuardDutyMatcher +from rules.matchers.matchers import AwsGuardDutyMatcher from streamalert.shared.rule import rule -@rule(logs=['cloudwatch:events'], matchers=[GuardDutyMatcher.guard_duty]) +@rule(logs=['cloudwatch:events'], matchers=[AwsGuardDutyMatcher.guard_duty]) def guard_duty_all(*_): """ author: spiper diff --git a/rules/matchers/matchers.py b/rules/matchers/matchers.py index 70382582c..3f924ebbf 100644 --- a/rules/matchers/matchers.py +++ b/rules/matchers/matchers.py @@ -14,7 +14,7 @@ @rule('root_logins', logs=['osquery:differential'], matchers=[matchers.prod, matchers.pci], outputs=['pagerduty:sample-integration']) """ -class GuardDutyMatcher: +class AwsGuardDutyMatcher: """A class contains matchers for AWS GuardDuty service""" @classmethod @@ -51,3 +51,38 @@ def user_login(cls, rec): int(rec['columns']['type']) == cls._EVENT_TYPE_LOGIN and (rec['columns']['username'] not in cls._RUNLEVELS) ) + + +class AwsConfigMatcher: + """Contains Matchers relevant to AWS Config""" + + @staticmethod + def is_config_compliance(rec): + """Check if the record event is from config compliance + + Args: + rec (dict): Parsed log to check key/value pairs + + Returns: + bool: True if from config and not in testMode else False + """ + return ( + rec['eventSource'] == 'config.amazonaws.com' + and rec['eventName'] == 'PutEvaluations' + and not rec['requestParameters']['testMode'] + ) + + @staticmethod + def is_auto_remediation(rec): + """Check if the record is an auto-remediation event + + Args: + rec (dict): Parsed log to check key/value pairs + Returns: + bool: True if auto_remediation event else False + """ + return ( + rec['eventName'] == 'StartAutomationExecution' + and rec['eventSource'] == 'ssm.amazonaws.com' + and rec['sourceIPAddress'] == 'config.amazonaws.com' + ) diff --git a/tests/integration/rules/cloudtrail/cloudtrail_aws_config.json b/tests/integration/rules/cloudtrail/cloudtrail_aws_config.json new file mode 100644 index 000000000..a3419ed0c --- /dev/null +++ b/tests/integration/rules/cloudtrail/cloudtrail_aws_config.json @@ -0,0 +1,199 @@ +[ + { + "data": { + "Records": [ + { + "additionalEventData": { + "configRuleArn": "...", + "configRuleInputParameters": "{}", + "configRuleName": "s3-bucket-logging-enabled", + "notificationJobType": "SCHEDULED_NOTIFICATION" + }, + "awsRegion": "...", + "eventID": "...", + "eventName": "PutEvaluations", + "eventSource": "config.amazonaws.com", + "eventTime": "...", + "eventType": "AwsApiCall", + "eventVersion": "1.05", + "recipientAccountId": "...", + "requestID": "...", + "requestParameters": { + "evaluations": [ + { + "complianceResourceId": "BUCKET_ONE", + "complianceResourceType": "AWS::S3::Bucket", + "complianceType": "NON_COMPLIANT", + "orderingTimestamp": "..." + }, + { + "complianceResourceId": "BUCKET_TWO", + "complianceResourceType": "AWS::S3::Bucket", + "complianceType": "COMPLIANT", + "orderingTimestamp": "..." + } + ], + "resultToken": "...", + "testMode": false + }, + "responseElements": null, + "sourceIPAddress": "...", + "userAgent": "...", + "userIdentity": { + "accessKeyId": "...", + "accountId": "...", + "arn": "...", + "principalId": "...", + "sessionContext": { + "attributes": { + "creationDate": "..." + }, + "sessionIssuer": { + "accountId": "...", + "arn": "...", + "principalId": "...", + "type": "Role", + "userName": "..." + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + } + ] + }, + "description": "Triggers an alert caused by a config compliance change of NON_COMPLIANT", + "log": "cloudtrail:events", + "service": "s3", + "source": "prefix.cluster.sample.bucket", + "trigger_rules": [ + "config_compliance" + ] + }, + { + "data": { + "Records": [ + { + "additionalEventData": { + "configRuleArn": "...", + "configRuleInputParameters": "{}", + "configRuleName": "s3-bucket-logging-enabled", + "notificationJobType": "SCHEDULED_NOTIFICATION" + }, + "awsRegion": "...", + "eventID": "...", + "eventName": "PutEvaluations", + "eventSource": "config.amazonaws.com", + "eventTime": "...", + "eventType": "AwsApiCall", + "eventVersion": "1.05", + "recipientAccountId": "...", + "requestID": "...", + "requestParameters": { + "evaluations": [ + { + "complianceResourceId": "BUCKET_ONE", + "complianceResourceType": "AWS::S3::Bucket", + "complianceType": "COMPLIANT", + "orderingTimestamp": "..." + }, + { + "complianceResourceId": "BUCKET_TWO", + "complianceResourceType": "AWS::S3::Bucket", + "complianceType": "COMPLIANT", + "orderingTimestamp": "..." + } + ], + "resultToken": "...", + "testMode": false + }, + "responseElements": null, + "sourceIPAddress": "...", + "userAgent": "...", + "userIdentity": { + "accessKeyId": "...", + "accountId": "...", + "arn": "...", + "principalId": "...", + "sessionContext": { + "attributes": { + "creationDate": "..." + }, + "sessionIssuer": { + "accountId": "...", + "arn": "...", + "principalId": "...", + "type": "Role", + "userName": "..." + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + } + ] + }, + "description": "Will not trigger an alert caused by a config compliance change of COMPLIANT", + "log": "cloudtrail:events", + "service": "s3", + "source": "prefix.cluster.sample.bucket", + "trigger_rules": [] + }, + { + "data": { + "Records": [ + { + "awsRegion": "eu-west-1", + "eventID": "...", + "eventName": "StartAutomationExecution", + "eventSource": "ssm.amazonaws.com", + "eventTime": "...", + "eventType": "...", + "eventVersion": "1.05", + "recipientAccountId": "...", + "requestID": "...", + "requestParameters": { + "domain": "vpc" + }, + "responseElements": { + "allocationId": "..", + "domain": "vpc", + "networkBorderGroup": "...", + "publicIp": "...", + "publicIpv4Pool": "amazon", + "requestId": "..." + }, + "sourceIPAddress": "config.amazonaws.com", + "userAgent": "...", + "userIdentity": { + "accessKeyId": "...", + "accountId": "...", + "arn": "...", + "principalId": "...", + "sessionContext": { + "attributes": { + "creationDate": "..." + }, + "sessionIssuer": { + "accountId": "...", + "arn": "...", + "principalId": "...", + "type": "Role", + "userName": "..." + }, + "webIdFederationData": {} + }, + "type": "AssumedRole" + } + } + ] + }, + "description": "Triggers an alert when auto-remediation of Config NON_COMPLIANT takes place", + "log": "cloudtrail:events", + "service": "s3", + "source": "prefix.cluster.sample.bucket", + "trigger_rules": [ + "config_auto_remediation" + ] + } +] \ No newline at end of file