From ce8dca0f0fb7d6989f40c12849781a11c4000324 Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Fri, 12 Jun 2020 21:10:13 -0500 Subject: [PATCH 1/7] restructure app layout --- auditors/__init__.py | 0 auditors/tests/__init__.py | 0 auditors/tests/test_AWS_Lambda_Auditor.py | 147 ------------------- auditors/tests/test_Amazon_SNS_Auditor.py | 167 ---------------------- requirements.txt | 1 + 5 files changed, 1 insertion(+), 314 deletions(-) delete mode 100644 auditors/__init__.py delete mode 100644 auditors/tests/__init__.py delete mode 100644 auditors/tests/test_AWS_Lambda_Auditor.py delete mode 100644 auditors/tests/test_Amazon_SNS_Auditor.py diff --git a/auditors/__init__.py b/auditors/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auditors/tests/__init__.py b/auditors/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/auditors/tests/test_AWS_Lambda_Auditor.py b/auditors/tests/test_AWS_Lambda_Auditor.py deleted file mode 100644 index 3963264d..00000000 --- a/auditors/tests/test_AWS_Lambda_Auditor.py +++ /dev/null @@ -1,147 +0,0 @@ -import datetime -import os -import pytest -from botocore.stub import Stubber, ANY -from auditors.AWS_Lambda_Auditor import ( - FunctionUnusedCheck, - sts, - lambda_client, - cloudwatch, -) - -# not available in local testing without ECS -os.environ["AWS_REGION"] = "us-east-1" -# for local testing, don't assume default profile exists -os.environ["AWS_DEFAULT_REGION"] = "us-east-1" - -sts_response = { - "Account": "012345678901", - "Arn": "arn:aws:iam::012345678901:user/user", -} - -list_functions_response = { - "Functions": [ - { - "FunctionName": "lambda-runner", - "FunctionArn": "arn:aws:lambda:us-east-1:012345678901:function:lambda-runner", - "LastModified": "2019-05-02T22:00:23.807+0000", - }, - ], -} - -get_metric_data_params = { - "EndTime": ANY, - "MetricDataQueries": ANY, - "StartTime": ANY, -} - -get_metric_data_empty_response = { - "MetricDataResults": [ - { - "Id": "m1", - "Label": "Invocations", - "Timestamps": [], - "Values": [], - "StatusCode": "Complete", - } - ], -} - -get_metric_data_response = { - "MetricDataResults": [ - { - "Id": "m1", - "Label": "Invocations", - "Timestamps": [datetime.datetime.now(datetime.timezone.utc)], - "Values": [3.0,], - "StatusCode": "Complete", - } - ], -} - - -@pytest.fixture(scope="function") -def sts_stubber(): - sts_stubber = Stubber(sts) - sts_stubber.activate() - yield sts_stubber - sts_stubber.deactivate() - - -@pytest.fixture(scope="function") -def lambda_stubber(): - lambda_stubber = Stubber(lambda_client) - lambda_stubber.activate() - yield lambda_stubber - lambda_stubber.deactivate() - - -@pytest.fixture(scope="function") -def cloudwatch_stubber(): - cloudwatch_stubber = Stubber(cloudwatch) - cloudwatch_stubber.activate() - yield cloudwatch_stubber - cloudwatch_stubber.deactivate() - - -def test_recent_use_lambda(lambda_stubber, cloudwatch_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - lambda_stubber.add_response("list_functions", list_functions_response) - cloudwatch_stubber.add_response( - "get_metric_data", get_metric_data_response, get_metric_data_params - ) - check = FunctionUnusedCheck() - results = check.execute() - for result in results: - if "lambda-runner" in result["Id"]: - assert result["RecordState"] == "ARCHIVED" - else: - assert False - lambda_stubber.assert_no_pending_responses() - cloudwatch_stubber.assert_no_pending_responses() - - -def test_no_activity_failure(lambda_stubber, cloudwatch_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - lambda_stubber.add_response("list_functions", list_functions_response) - cloudwatch_stubber.add_response( - "get_metric_data", get_metric_data_empty_response, get_metric_data_params - ) - check = FunctionUnusedCheck() - results = check.execute() - for result in results: - if "lambda-runner" in result["Id"]: - assert result["RecordState"] == "ACTIVE" - else: - assert False - lambda_stubber.assert_no_pending_responses() - cloudwatch_stubber.assert_no_pending_responses() - - -def test_recently_updated(lambda_stubber, cloudwatch_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - list_functions_recent_update_response = { - "Functions": [ - { - "FunctionName": "lambda-runner", - "FunctionArn": "arn:aws:lambda:us-east-1:012345678901:function:lambda-runner", - "LastModified": ( - datetime.datetime.now(datetime.timezone.utc) - - datetime.timedelta(days=1) - ).isoformat(), - }, - ], - } - lambda_stubber.add_response("list_functions", list_functions_recent_update_response) - cloudwatch_stubber.add_response( - "get_metric_data", get_metric_data_empty_response, get_metric_data_params - ) - check = FunctionUnusedCheck() - results = check.execute() - for result in results: - if "lambda-runner" in result["Id"]: - assert result["RecordState"] == "ARCHIVED" - else: - assert False - lambda_stubber.assert_no_pending_responses() - cloudwatch_stubber.assert_no_pending_responses() diff --git a/auditors/tests/test_Amazon_SNS_Auditor.py b/auditors/tests/test_Amazon_SNS_Auditor.py deleted file mode 100644 index 430b3db5..00000000 --- a/auditors/tests/test_Amazon_SNS_Auditor.py +++ /dev/null @@ -1,167 +0,0 @@ -import datetime -import json -import os -import pytest -from botocore.stub import Stubber, ANY -from auditors.Amazon_SNS_Auditor import ( - SNSTopicEncryptionCheck, - SNSHTTPEncryptionCheck, - SNSPublicAccessCheck, - SNSCrossAccountCheck, - sts, - sns, -) - -# not available in local testing without ECS -os.environ["AWS_REGION"] = "us-east-1" -# for local testing, don't assume default profile exists -os.environ["AWS_DEFAULT_REGION"] = "us-east-1" - -sts_response = { - "Account": "012345678901", - "Arn": "arn:aws:iam::012345678901:user/user", -} - -list_topics_response = { - "Topics": [{"TopicArn": "arn:aws:sns:us-east-1:012345678901:MyTopic"},], -} - -get_topic_attributes_arn_response = { - "Attributes": { - "Policy": '{"Statement":[{"Principal":{"AWS":"arn:aws:iam::012345678901:root"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', - } -} -get_topic_attributes_only_id_response = { - "Attributes": { - "Policy": '{"Statement":[{"Principal":{"AWS":"012345678901"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', - } -} - -get_topic_attributes_wrong_id_response = { - "Attributes": { - "Policy": '{"Statement":[{"Principal":{"AWS":"arn:aws:iam::012345678902:root"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', - } -} - -get_topic_attributes_response1 = { - "Attributes": { - "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::012345678901:root"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test"}]}' - } -} - -get_topic_attributes_response2 = { - "Attributes": { - "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic","SNS:Subscribe","SNS:ListSubscriptionsByTopic","SNS:Publish","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test","Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}' - } -} - -get_topic_attributes_response3 = { - "Attributes": { - "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test","Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}},{"Sid":"__console_pub_0","Effect":"Allow","Principal":{"AWS":"*"},"Action":"SNS:Publish","Resource":"arn:aws:sns:us-east-1:012345678901:Test"},{"Sid":"__console_sub_0","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:Subscribe","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test"}]}' - } -} - - -@pytest.fixture(scope="function") -def sts_stubber(): - sts_stubber = Stubber(sts) - sts_stubber.activate() - yield sts_stubber - sts_stubber.deactivate() - - -@pytest.fixture(scope="function") -def sns_stubber(): - sns_stubber = Stubber(sns) - sns_stubber.activate() - yield sns_stubber - sns_stubber.deactivate() - - -def test_id_arn_is_principal(sns_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response("get_topic_attributes", get_topic_attributes_arn_response) - check = SNSCrossAccountCheck() - results = check.execute() - for result in results: - if "MyTopic" in result["Id"]: - print(result["Id"]) - assert result["RecordState"] == "ARCHIVED" - else: - assert False - sns_stubber.assert_no_pending_responses() - - -def test_id_is_principal(sns_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response( - "get_topic_attributes", get_topic_attributes_only_id_response - ) - check = SNSCrossAccountCheck() - results = check.execute() - for result in results: - if "MyTopic" in result["Id"]: - print(result["Id"]) - assert result["RecordState"] == "ARCHIVED" - else: - assert False - sns_stubber.assert_no_pending_responses() - - -def test_id_not_principal(sns_stubber, sts_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response( - "get_topic_attributes", get_topic_attributes_wrong_id_response - ) - check = SNSCrossAccountCheck() - results = check.execute() - for result in results: - if "MyTopic" in result["Id"]: - print(result["Id"]) - assert result["RecordState"] == "ACTIVE" - sns_stubber.assert_no_pending_responses() - - -def test_no_access(sts_stubber, sns_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response1) - check = SNSPublicAccessCheck() - results = check.execute() - for result in results: - if "Test" in result["Id"]: - assert result["RecordState"] == "ARCHIVED" - else: - assert False - sns_stubber.assert_no_pending_responses() - - -def test_has_a_condition(sts_stubber, sns_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response2) - check = SNSPublicAccessCheck() - results = check.execute() - for result in results: - if "Test" in result["Id"]: - assert result["RecordState"] == "ARCHIVED" - else: - assert False - sns_stubber.assert_no_pending_responses() - - -def test_has_public_access(sts_stubber, sns_stubber): - sts_stubber.add_response("get_caller_identity", sts_response) - sns_stubber.add_response("list_topics", list_topics_response) - sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response3) - check = SNSPublicAccessCheck() - results = check.execute() - for result in results: - if "Test" in result["Id"]: - assert result["RecordState"] == "ARCHIVED" - else: - assert False - sns_stubber.assert_no_pending_responses() diff --git a/requirements.txt b/requirements.txt index 2cbde825..32fcf7c7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ awscli boto3 requests +pluginbase From b4b975209da7124afa7c398b058296bfb7c824ed Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Fri, 12 Jun 2020 21:10:37 -0500 Subject: [PATCH 2/7] cleanup --- auditors/AMI_Auditor.py | 282 -- auditors/AWS_AppMesh_Auditor.py | 643 --- auditors/AWS_Backup_Auditor.py | 722 --- auditors/AWS_CloudFormation_Auditor.py | 271 -- auditors/AWS_CloudTrail_Auditor.py | 597 --- auditors/AWS_CodeBuild_Auditor.py | 775 ---- auditors/AWS_DMS_Auditor.py | 387 -- auditors/AWS_Directory_Service_Auditor.py | 291 -- auditors/AWS_Glue_Auditor.py | 814 ---- auditors/AWS_IAM_Auditor.py | 1106 ----- auditors/AWS_Lambda_Auditor.py | 169 - auditors/AWS_License_Manager_Auditor.py | 162 - auditors/AWS_Secrets_Manager_Auditor.py | 329 -- auditors/AWS_Security_Hub_Auditor.py | 170 - auditors/AWS_Security_Services_Auditor.py | 369 -- auditors/Amazon_APIGW_Auditor.py | 1082 ----- auditors/Amazon_AppStream_Auditor.py | 542 --- auditors/Amazon_CognitoIdP_Auditor.py | 541 --- auditors/Amazon_DocumentDB_Auditor.py | 1330 ------ auditors/Amazon_EBS_Auditor.py | 885 ---- auditors/Amazon_EC2_Auditor.py | 199 - auditors/Amazon_EC2_SSM_Auditor.py | 759 --- auditors/Amazon_EC2_Security_Group_Auditor.py | 4068 ----------------- auditors/Amazon_ECR_Auditor.py | 610 --- auditors/Amazon_ECS_Auditor.py | 317 -- auditors/Amazon_EFS_Auditor.py | 165 - auditors/Amazon_EKS_Auditor.py | 469 -- auditors/Amazon_ELB_Auditor.py | 769 ---- auditors/Amazon_ELBv2_Auditor.py | 1072 ----- auditors/Amazon_EMR_Auditor.py | 1400 ------ auditors/Amazon_Elasticache_Redis_Auditor.py | 536 --- .../Amazon_ElasticsearchService_Auditor.py | 1157 ----- .../Amazon_Kinesis_Data_Streams_Auditor.py | 296 -- auditors/Amazon_Kinesis_Firehose_Auditor.py | 176 - auditors/Amazon_MQ_Auditor.py | 773 ---- auditors/Amazon_MSK_Auditor.py | 577 --- auditors/Amazon_Managed_Blockchain_Auditor.py | 564 --- auditors/Amazon_Neptune_Auditor.py | 750 --- auditors/Amazon_RDS_Auditor.py | 1619 ------- auditors/Amazon_Redshift_Auditor.py | 513 --- auditors/Amazon_S3_Auditor.py | 865 ---- auditors/Amazon_SNS_Auditor.py | 611 --- auditors/Amazon_SageMaker_Auditor.py | 662 --- auditors/Amazon_Shield_Advanced_Auditor.py | 1222 ----- auditors/Amazon_VPC_Auditor.py | 277 -- auditors/Amazon_WorkSpaces_Auditor.py | 596 --- auditors/Auditor.py | 77 - auditors/Shodan_Auditor.py | 1294 ------ 48 files changed, 33860 deletions(-) delete mode 100644 auditors/AMI_Auditor.py delete mode 100644 auditors/AWS_AppMesh_Auditor.py delete mode 100644 auditors/AWS_Backup_Auditor.py delete mode 100644 auditors/AWS_CloudFormation_Auditor.py delete mode 100644 auditors/AWS_CloudTrail_Auditor.py delete mode 100644 auditors/AWS_CodeBuild_Auditor.py delete mode 100644 auditors/AWS_DMS_Auditor.py delete mode 100644 auditors/AWS_Directory_Service_Auditor.py delete mode 100644 auditors/AWS_Glue_Auditor.py delete mode 100644 auditors/AWS_IAM_Auditor.py delete mode 100644 auditors/AWS_Lambda_Auditor.py delete mode 100644 auditors/AWS_License_Manager_Auditor.py delete mode 100644 auditors/AWS_Secrets_Manager_Auditor.py delete mode 100644 auditors/AWS_Security_Hub_Auditor.py delete mode 100644 auditors/AWS_Security_Services_Auditor.py delete mode 100644 auditors/Amazon_APIGW_Auditor.py delete mode 100644 auditors/Amazon_AppStream_Auditor.py delete mode 100644 auditors/Amazon_CognitoIdP_Auditor.py delete mode 100644 auditors/Amazon_DocumentDB_Auditor.py delete mode 100644 auditors/Amazon_EBS_Auditor.py delete mode 100644 auditors/Amazon_EC2_Auditor.py delete mode 100644 auditors/Amazon_EC2_SSM_Auditor.py delete mode 100644 auditors/Amazon_EC2_Security_Group_Auditor.py delete mode 100644 auditors/Amazon_ECR_Auditor.py delete mode 100644 auditors/Amazon_ECS_Auditor.py delete mode 100644 auditors/Amazon_EFS_Auditor.py delete mode 100644 auditors/Amazon_EKS_Auditor.py delete mode 100644 auditors/Amazon_ELB_Auditor.py delete mode 100644 auditors/Amazon_ELBv2_Auditor.py delete mode 100644 auditors/Amazon_EMR_Auditor.py delete mode 100644 auditors/Amazon_Elasticache_Redis_Auditor.py delete mode 100644 auditors/Amazon_ElasticsearchService_Auditor.py delete mode 100644 auditors/Amazon_Kinesis_Data_Streams_Auditor.py delete mode 100644 auditors/Amazon_Kinesis_Firehose_Auditor.py delete mode 100644 auditors/Amazon_MQ_Auditor.py delete mode 100644 auditors/Amazon_MSK_Auditor.py delete mode 100644 auditors/Amazon_Managed_Blockchain_Auditor.py delete mode 100644 auditors/Amazon_Neptune_Auditor.py delete mode 100644 auditors/Amazon_RDS_Auditor.py delete mode 100644 auditors/Amazon_Redshift_Auditor.py delete mode 100644 auditors/Amazon_S3_Auditor.py delete mode 100644 auditors/Amazon_SNS_Auditor.py delete mode 100644 auditors/Amazon_SageMaker_Auditor.py delete mode 100644 auditors/Amazon_Shield_Advanced_Auditor.py delete mode 100644 auditors/Amazon_VPC_Auditor.py delete mode 100644 auditors/Amazon_WorkSpaces_Auditor.py delete mode 100644 auditors/Auditor.py delete mode 100644 auditors/Shodan_Auditor.py diff --git a/auditors/AMI_Auditor.py b/auditors/AMI_Auditor.py deleted file mode 100644 index 5b7dbe14..00000000 --- a/auditors/AMI_Auditor.py +++ /dev/null @@ -1,282 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -ec2 = boto3.client('ec2') -sts = boto3.client('sts') -# create account id & region variables -awsAccount = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# find AMIs created by the account -response = ec2.describe_images(Filters=[ { 'Name': 'owner-id','Values': [ awsAccount ] } ],DryRun=False) -myAmis = response['Images'] - -class PublicAMICheck(Auditor): - def execute(self): - for ami in myAmis: - imageId = str(ami['ImageId']) - amiArn = 'arn:aws:ec2:' + awsRegion + '::image/' + imageId - imageName = str(ami['Name']) - imageCreatedDate = str(ami['CreationDate']) - publicCheck = str(ami['Public']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if publicCheck == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': amiArn + '/public-ami', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': amiArn, - 'AwsAccountId': awsAccount, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'CRITICAL' }, - 'Confidence': 99, - 'Title': '[AMI.1] Self-managed Amazon Machine Images (AMIs) should not be public', - 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is exposed to the public. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your AMI is not intended to be public refer to the Sharing an AMI with Specific AWS Accounts section of the EC2 user guide', - 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharingamis-explicit.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': amiArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': amiArn + '/public-ami', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': amiArn, - 'AwsAccountId': awsAccount, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AMI.1] Self-managed Amazon Machine Images (AMIs) should not be public', - 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is private.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your AMI is not intended to be public refer to the Sharing an AMI with Specific AWS Accounts section of the EC2 user guide', - 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharingamis-explicit.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': amiArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'REVOKED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class EncryptedAMICheck(Auditor): - def execute(self): - for ami in myAmis: - imageId = str(ami['ImageId']) - amiArn = 'arn:aws:ec2:' + awsRegion + '::image/' + imageId - imageName = str(ami['Name']) - imageCreatedDate = str(ami['CreationDate']) - BlockDevices = ami['BlockDeviceMappings'] - for ebsmapping in BlockDevices: - encryptionCheck = str(ebsmapping['Ebs']['Encrypted']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if encryptionCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': amiArn + '/public-ami', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': amiArn, - 'AwsAccountId': awsAccount, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[AMI.2] Self-managed Amazon Machine Images (AMIs) should be encrypted', - 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is not encrypted. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your AMI should be encrypted refer to the Image-Copying Scenarios section of the EC2 user guide', - 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#AMI-encryption-copy' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': amiArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': amiArn + '/public-ami', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': amiArn, - 'AwsAccountId': awsAccount, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AMI.2] Self-managed Amazon Machine Images (AMIs) should be encrypted', - 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is encrypted.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your AMI should be encrypted refer to the Image-Copying Scenarios section of the EC2 user guide', - 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#AMI-encryption-copy' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': amiArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/AWS_AppMesh_Auditor.py b/auditors/AWS_AppMesh_Auditor.py deleted file mode 100644 index 9279ce2b..00000000 --- a/auditors/AWS_AppMesh_Auditor.py +++ /dev/null @@ -1,643 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -appmesh = boto3.client('appmesh') -sts = boto3.client('sts') -# create account id & region variables -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# loop through AWS App Mesh meshes -try: - response = appmesh.list_meshes() - myMesh = response['meshes'] -except Exception as e: - print(e) - -class AppmeshMeshEgressCheck(Auditor): - def execute(self): - for meshes in myMesh: - meshName = str(meshes['meshName']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = appmesh.describe_mesh(meshName=meshName) - meshArn = str(response['mesh']['metadata']['arn']) - egressSpecCheck = str(response['mesh']['spec']['egressFilter']['type']) - if egressSpecCheck != 'DROP_ALL': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': meshArn + '/appmesh-mesh-egress-filter-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': meshArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[AppMesh.1] App Mesh meshes should have the egress filter configured to DROP_ALL', - 'Description': 'App Mesh mesh ' + meshName + ' egress filter is not configured to DROP_ALL. Configuring the filter to DROP_ALL only allows egress to other resources in the mesh and to AWS SPNs for API Calls. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on egress filters refer to the EgressFilter Data Type section of the AWS App Mesh API Reference', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/APIReference/API_EgressFilter.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': meshArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': meshArn + '/appmesh-mesh-egress-filter-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': meshArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AppMesh.1] App Mesh meshes should have the egress filter configured to DROP_ALL', - 'Description': 'App Mesh mesh ' + meshName + ' egress filter is configured to DROP_ALL.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on egress filters refer to the EgressFilter Data Type section of the AWS App Mesh API Reference', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/APIReference/API_EgressFilter.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': meshArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class AppmeshVirtNodeBackendDefaultTLSpolicyCheck(Auditor): - def execute(self): - for meshes in myMesh: - meshName = str(meshes['meshName']) - try: - response = appmesh.list_virtual_nodes(meshName=meshName) - for nodes in response['virtualNodes']: - nodeName = str(nodes['virtualNodeName']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) - nodeArn = str(response['virtualNode']['metadata']['arn']) - backendDefaultsCheck = str(response['virtualNode']['spec']['backendDefaults']['clientPolicy']) - if backendDefaultsCheck == '{}': - # this is a type of failing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not have a backend default client policy configured. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-2', - 'NIST SP 800-53 SC-8', - 'NIST SP 800-53 SC-11', - 'NIST SP 800-53 SC-12', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.13.2.3', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - backendTlsEnforceCheck = str(response['virtualNode']['spec']['backendDefaults']['clientPolicy']['tls']['enforce']) - if backendTlsEnforceCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not enforce TLS in the default client policy. TLS will encrypt the traffic in between the Envoy virtual nodes in your mesh to offload the responsibility from your application code and will also terminate TLS for you. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-2', - 'NIST SP 800-53 SC-8', - 'NIST SP 800-53 SC-11', - 'NIST SP 800-53 SC-12', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.13.2.3', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' enforces TLS in the default client policy.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-2', - 'NIST SP 800-53 SC-8', - 'NIST SP 800-53 SC-11', - 'NIST SP 800-53 SC-12', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.13.2.3', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - -class AppmeshVirtNodeListenerStrictTLScheck(Auditor): - def execute(self): - for meshes in myMesh: - meshName = str(meshes['meshName']) - try: - response = appmesh.list_virtual_nodes(meshName=meshName) - for nodes in response['virtualNodes']: - nodeName = str(nodes['virtualNodeName']) - try: - response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) - nodeArn = str(response['virtualNode']['metadata']['arn']) - for listeners in response['virtualNode']['spec']['listeners']: - tlsStrictCheck = str(listeners['tls']['mode']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if tlsStrictCheck != 'STRICT': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-listener-strict-tls-mode-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[AppMesh.3] App Mesh virtual node listeners should only accept connections with TLS enabled', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not enforce STRICT mode for listeners. Not setting a STRICT listener mode will accept non-encrypted connections to the listeners in the node. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-2', - 'NIST SP 800-53 SC-8', - 'NIST SP 800-53 SC-11', - 'NIST SP 800-53 SC-12', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.13.2.3', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-listener-strict-tls-mode-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AppMesh.3] App Mesh virtual node listeners should only accept connections with TLS enabled', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' enforces STRICT mode for listeners.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-2', - 'NIST SP 800-53 SC-8', - 'NIST SP 800-53 SC-11', - 'NIST SP 800-53 SC-12', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.13.2.3', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'tls'": - pass - else: - print(e) - except Exception as e: - print(e) - -class AppmeshLoggingCheck(Auditor): - def execute(self): - for meshes in myMesh: - meshName = str(meshes['meshName']) - try: - response = appmesh.list_virtual_nodes(meshName=meshName) - for nodes in response['virtualNodes']: - nodeName = str(nodes['virtualNodeName']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) - nodeArn = str(response['virtualNode']['metadata']['arn']) - loggingCheck = str(response['virtualNode']['spec']['logging']) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-access-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[AppMesh.4] App Mesh virtual nodes should define an HTTP access log path to enable log exports for Envoy proxies', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' specifies a path for HTTP access logs.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring access logging for virtual nodes refer to the Creating a Virtual Node section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_nodes.html#vn-create-virtual-node' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName, - 'accessLogPath': loggingCheck - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'logging'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': nodeArn + '/appmesh-virtual-node-access-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': nodeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[AppMesh.4] App Mesh virtual nodes should define an HTTP access log path to enable log exports for Envoy proxies', - 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not specify a path for HTTP access logs. Specifying a path will allow you to use Docker log drivers or otherwise to pipe logs out of Envoy to another service such as CloudWatch. Refer to the remediation instructions if this configuration is not intended.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring access logging for virtual nodes refer to the Creating a Virtual Node section of the AWS App Mesh User Guide', - 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_nodes.html#vn-create-virtual-node' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': nodeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'meshName': meshName, - 'virtualNodeName': nodeName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - except Exception as e: - print(e) diff --git a/auditors/AWS_Backup_Auditor.py b/auditors/AWS_Backup_Auditor.py deleted file mode 100644 index 66fa52f7..00000000 --- a/auditors/AWS_Backup_Auditor.py +++ /dev/null @@ -1,722 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -sts = boto3.client('sts') -ec2 = boto3.client('ec2') -dynamodb = boto3.client('dynamodb') -rds = boto3.client('rds') -efs = boto3.client('efs') -backup = boto3.client('backup') -# create env vars -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] - -class VolumeBackupCheck(Auditor): - def execute(self): - # loop through available or in-use ebs volumes - response = ec2.describe_volumes(Filters=[{'Name': 'status','Values': ['available', 'in-use']}]) - myEbsVolumes = response['Volumes'] - for volumes in myEbsVolumes: - volumeId = str(volumes['VolumeId']) - volumeArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + ':volume/' + volumeId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - # check if ebs volumes are backed up - response = backup.describe_protected_resource(ResourceArn=volumeArn) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': volumeArn + '/ebs-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': volumeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Backup.1] EBS volumes should be protected by AWS Backup', - 'Description': 'EBS volume ' + volumeId + ' is protected by AWS Backup', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Volume', - 'Id': volumeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'volumeId': volumeId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': volumeArn + '/ebs-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': volumeArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Backup.1] EBS volumes should be protected by AWS Backup', - 'Description': 'EBS volume ' + volumeId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EBS volumes', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Volume', - 'Id': volumeArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'volumeId': volumeId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class EC2BackupCheck(Auditor): - def execute(self): - # loop through ec2 instances - response = ec2.describe_instances(DryRun=False) - myReservations = response['Reservations'] - for reservations in myReservations: - myInstances = reservations['Instances'] - for instances in myInstances: - instanceId = str(instances['InstanceId']) - instanceType = str(instances['InstanceType']) - imageId = str(instances['ImageId']) - subnetId = str(instances['SubnetId']) - vpcId = str(instances['VpcId']) - instanceArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + ':instance/' + instanceId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - # check if ec2 instances are backed up - response = backup.describe_protected_resource(ResourceArn=instanceArn) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': instanceArn + '/ec2-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': instanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Backup.2] EC2 instances should be protected by AWS Backup', - 'Description': 'EC2 instance ' + instanceId + ' is protected by AWS Backup.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Instance', - 'Id': instanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsEc2Instance': { - 'Type': instanceType, - 'ImageId': imageId, - 'VpcId': vpcId, - 'SubnetId': subnetId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': instanceArn + '/ec2-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': instanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Backup.2] EC2 instances should be protected by AWS Backup', - 'Description': 'EC2 instance ' + instanceId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EC2 instances', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Instance', - 'Id': instanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsEc2Instance': { - 'Type': instanceType, - 'ImageId': imageId, - 'VpcId': vpcId, - 'SubnetId': subnetId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class ddbBackupCheck(Auditor): - def execute(self): - # loop through dynamodb tables - response = dynamodb.list_tables() - myDdbTables = response['TableNames'] - for tables in myDdbTables: - response = dynamodb.describe_table(TableName=tables) - tableArn = str(response['Table']['TableArn']) - tableName = str(response['Table']['TableName']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - # check if ddb tables are backed up - response = backup.describe_protected_resource(ResourceArn=tableArn) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': tableArn + '/dynamodb-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': tableArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Backup.3] DynamoDB tables should be protected by AWS Backup', - 'Description': 'DynamoDB table ' + tableName + ' is protected by AWS Backup.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsDynamoDbTable', - 'Id': tableArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'tableName': tableName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': tableArn + '/dynamodb-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': tableArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Backup.3] DynamoDB tables should be protected by AWS Backup', - 'Description': 'DynamoDB table ' + tableName + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for DynamoDB tables', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsDynamoDbTable', - 'Id': tableArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'tableName': tableName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class rdsBackupCheck(Auditor): - def execute(self): - # loop through rds db instances - response = rds.describe_db_instances( - Filters=[ - { - 'Name': 'engine', - 'Values': [ - 'aurora', - 'aurora-mysql', - 'aurora-postgresql', - 'mariadb', - 'mysql', - 'oracle-ee', - 'postgres', - 'sqlserver-ee', - 'sqlserver-se', - 'sqlserver-ex', - 'sqlserver-web' - ] - } - ], - MaxRecords=100 - ) - myRdsInstances = response['DBInstances'] - for databases in myRdsInstances: - dbArn = str(databases['DBInstanceArn']) - dbId = str(databases['DBInstanceIdentifier']) - dbEngine = str(databases['Engine']) - dbEngineVersion = str(databases['EngineVersion']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - # check if db instances are backed up - response = backup.describe_protected_resource(ResourceArn=dbArn) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dbArn + '/rds-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dbArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Backup.4] RDS database instances should be protected by AWS Backup', - 'Description': 'RDS database instance ' + dbId + ' is protected by AWS Backup.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsRdsDbInstance', - 'Id': dbArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsRdsDbInstance': { - 'DBInstanceIdentifier': dbId, - 'Engine': dbEngine, - 'EngineVersion': dbEngineVersion - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding={ - 'SchemaVersion': '2018-10-08', - 'Id': dbArn + '/rds-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dbArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Backup.4] RDS database instances should be protected by AWS Backup', - 'Description': 'RDS database instance ' + dbId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for RDS instances', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsRdsDbInstance', - 'Id': dbArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsRdsDbInstance': { - 'DBInstanceIdentifier': dbId, - 'Engine': dbEngine, - 'EngineVersion': dbEngineVersion - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class efsBackupCheck(Auditor): - def execute(self): - # loop through EFS file systems - response = efs.describe_file_systems() - myFileSys = response['FileSystems'] - for filesys in myFileSys: - fileSysId = str(filesys['FileSystemId']) - fileSysArn = 'arn:aws:elasticfilesystem:' + awsRegion + ':' + awsAccountId + ':file-system/' + fileSysId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - # check if db instances are backed up - response = backup.describe_protected_resource(ResourceArn=fileSysArn) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': fileSysArn + '/efs-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': fileSysArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Backup.5] EFS file systems should be protected by AWS Backup', - 'Description': 'EFS file system ' + fileSysId + ' is protected by AWS Backup.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsElasticFileSystem', - 'Id': fileSysArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'fileSystemId': fileSysId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': fileSysArn + '/efs-backups', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': fileSysArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Backup.5] EFS file systems should be protected by AWS Backup', - 'Description': 'EFS file system ' + fileSysId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EFS file systems.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', - 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsElasticFileSystem', - 'Id': fileSysArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'fileSystemId': fileSysId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - \ No newline at end of file diff --git a/auditors/AWS_CloudFormation_Auditor.py b/auditors/AWS_CloudFormation_Auditor.py deleted file mode 100644 index 34ff51f3..00000000 --- a/auditors/AWS_CloudFormation_Auditor.py +++ /dev/null @@ -1,271 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -cloudformation = boto3.client('cloudformation') -# create env vars for account and region -#awsRegion = os.environ['AWS_REGION'] -awsRegion = 'us-east-1' -awsAccountId = sts.get_caller_identity()['Account'] -# describe all cfn stacks -response = cloudformation.describe_stacks() -myCfnStacks = response['Stacks'] - -class cfnDriftCheck(Auditor): - def execute(self): - for stacks in myCfnStacks: - stackName = str(stacks['StackName']) - stackId = str(stacks['StackId']) - stackArn = 'arn:aws:cloudformation:' + awsRegion + ':' + awsAccountId + ':stack/' + stackName + '/' + stackId - driftCheck = str(stacks['DriftInformation']['StackDriftStatus']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if driftCheck != 'IN_SYNC': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': stackArn + '/cloudformation-drift-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': stackArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[CloudFormation.1] CloudFormation stacks should be monitored for configuration drift', - 'Description': 'CloudFormation stack ' + stackName + ' has not been monitored for drift detection. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'To learn more about drift detection refer to the Detecting Unmanaged Configuration Changes to Stacks and Resources section of the AWS CloudFormation User Guide', - 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudFormationStack', - 'Id': stackArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'stackName': stackName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.MA-1', - 'NIST SP 800-53 MA-2', - 'NIST SP 800-53 MA-3', - 'NIST SP 800-53 MA-5', - 'NIST SP 800-53 MA-6', - 'AICPA TSC CC8.1', - 'ISO 27001:2013 A.11.1.2', - 'ISO 27001:2013 A.11.2.4', - 'ISO 27001:2013 A.11.2.5', - 'ISO 27001:2013 A.11.2.6' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': stackArn + '/cloudformation-drift-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': stackArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudFormation.1] CloudFormation stacks should be monitored for configuration drift', - 'Description': 'CloudFormation stack ' + stackName + ' has been monitored for drift detection.', - 'Remediation': { - 'Recommendation': { - 'Text': 'To learn more about drift detection refer to the Detecting Unmanaged Configuration Changes to Stacks and Resources section of the AWS CloudFormation User Guide', - 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudFormationStack', - 'Id': stackArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'stackName': stackName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.MA-1', - 'NIST SP 800-53 MA-2', - 'NIST SP 800-53 MA-3', - 'NIST SP 800-53 MA-5', - 'NIST SP 800-53 MA-6', - 'AICPA TSC CC8.1', - 'ISO 27001:2013 A.11.1.2', - 'ISO 27001:2013 A.11.2.4', - 'ISO 27001:2013 A.11.2.5', - 'ISO 27001:2013 A.11.2.6' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class cfnMonitoringCheck(Auditor): - def execute(self): - for stacks in myCfnStacks: - stackName = str(stacks['StackName']) - stackId = str(stacks['StackId']) - stackArn = 'arn:aws:cloudformation:' + awsRegion + ':' + awsAccountId + ':stack/' + stackName + '/' + stackId - alertsCheck = str(stacks['NotificationARNs']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if alertsCheck == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': stackArn + '/cloudformation-monitoring-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': stackArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[CloudFormation.2] CloudFormation stacks should be monitored for changes', - 'Description': 'CloudFormation stack ' + stackName + ' does not have monitoring enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your stack should having monitoring enabled refer to the Monitor and Roll Back Stack Operations section of the AWS CloudFormation User Guide', - 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-rollback-triggers.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudFormationStack', - 'Id': stackArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'stackName': stackName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': stackArn + '/cloudformation-monitoring-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': stackArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudFormation.2] CloudFormation stacks should be monitored for changes', - 'Description': 'CloudFormation stack ' + stackName + ' has monitoring enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your stack should having monitoring enabled refer to the Monitor and Roll Back Stack Operations section of the AWS CloudFormation User Guide', - 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-rollback-triggers.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudFormationStack', - 'Id': stackArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'stackName': stackName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/AWS_CloudTrail_Auditor.py b/auditors/AWS_CloudTrail_Auditor.py deleted file mode 100644 index f7284724..00000000 --- a/auditors/AWS_CloudTrail_Auditor.py +++ /dev/null @@ -1,597 +0,0 @@ -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -cloudtrail = boto3.client('cloudtrail') -sts = boto3.client('sts') -# create account id & region variables -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# loop through trails -response = cloudtrail.list_trails() -myCloudTrails = response['Trails'] - -class CloudtrailMultiRegionCheck(Auditor): - def execute(self): - for trails in myCloudTrails: - trailArn = str(trails['TrailARN']) - trailName = str(trails['Name']) - response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - for details in response['trailList']: - multiRegionCheck = str(details['IsMultiRegionTrail']) - if multiRegionCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-multi-region-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[CloudTrail.1] CloudTrail trails should be multi-region', - 'Description': 'CloudTrail trail ' + trailName + ' is not a multi-region trail. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should be multi-region refer to the Receiving CloudTrail Log Files from Multiple Regions section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-multi-region-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudTrail.1] CloudTrail trails should be multi-region', - 'Description': 'CloudTrail trail ' + trailName + ' is a multi-region trail.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should be multi-region refer to the Receiving CloudTrail Log Files from Multiple Regions section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class CloudtrailCloudwatchLoggingCheck(Auditor): - def execute(self): - for trails in myCloudTrails: - trailArn = str(trails['TrailARN']) - trailName = str(trails['Name']) - response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - for details in response['trailList']: - try: - # this is a passing check - cloudwatchLogCheck = str(details['CloudWatchLogsLogGroupArn']) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-cloudwatch-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudTrail.2] CloudTrail trails should have CloudWatch logging configured', - 'Description': 'CloudTrail trail ' + trailName + ' has CloudWatch Logging configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should send logs to CloudWatch refer to the Monitoring CloudTrail Log Files with Amazon CloudWatch Logs section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/monitor-cloudtrail-log-files-with-cloudwatch-logs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'CloudWatchLogsLogGroupArn'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-cloudwatch-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[CloudTrail.2] CloudTrail trails should have CloudWatch logging configured', - 'Description': 'CloudTrail trail ' + trailName + ' does not have CloudWatch Logging configured. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should send logs to CloudWatch refer to the Monitoring CloudTrail Log Files with Amazon CloudWatch Logs section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/monitor-cloudtrail-log-files-with-cloudwatch-logs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class CloudtrailEncryptionCheck(Auditor): - def execute(self): - for trails in myCloudTrails: - trailArn = str(trails['TrailARN']) - trailName = str(trails['Name']) - response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - for details in response['trailList']: - try: - # this is a passing check - encryptionCheck = str(details['KmsKeyId']) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-kms-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudTrail.3] CloudTrail trails should be encrypted by KMS', - 'Description': 'CloudTrail trail ' + trailName + ' is encrypted by KMS.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should be encrypted with SSE-KMS refer to the Encrypting CloudTrail Log Files with AWS KMS–Managed Keys (SSE-KMS) section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'KmsKeyId'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-kms-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[CloudTrail.3] CloudTrail trails should be encrypted by KMS', - 'Description': 'CloudTrail trail ' + trailName + ' is not encrypted by KMS. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should be encrypted with SSE-KMS refer to the Encrypting CloudTrail Log Files with AWS KMS–Managed Keys (SSE-KMS) section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class CloudtrailGlobalServicesCheck(Auditor): - def execute(self): - for trails in myCloudTrails: - trailArn = str(trails['TrailARN']) - trailName = str(trails['Name']) - response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - for details in response['trailList']: - globalServiceEventCheck = str(details['IncludeGlobalServiceEvents']) - if globalServiceEventCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-global-services-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[CloudTrail.4] CloudTrail trails should log management events', - 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should log management events refer to the Management Events section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-events-with-cloudtrail.html#logging-management-events' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-global-services-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudTrail.4] CloudTrail trails should log management events', - 'Description': 'CloudTrail trail ' + trailName + ' logs management events.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should log management events refer to the Management Events section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-events-with-cloudtrail.html#logging-management-events' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class CloudtrailLogFileValidationCheck(Auditor): - def execute(self): - for trails in myCloudTrails: - trailArn = str(trails['TrailARN']) - trailName = str(trails['Name']) - response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - for details in response['trailList']: - fileValidationCheck = str(details['LogFileValidationEnabled']) - if fileValidationCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-log-file-validation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[CloudTrail.5] CloudTrail log file validation should be enabled', - 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should have log file validation enabled refer to the Validating CloudTrail Log File Integrity section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-6', - 'NIST SP 800-53 SC-16', - 'NIST SP 800-53 SI-7', - 'AICPA TSC CC7.1', - 'ISO 27001:2013 A.12.2.1', - 'ISO 27001:2013 A.12.5.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3', - 'ISO 27001:2013 A.14.2.4' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': trailArn + '/cloudtrail-log-file-validation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': trailArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[CloudTrail.5] CloudTrail log file validation should be enabled', - 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If your trail should have log file validation enabled refer to the Validating CloudTrail Log File Integrity section of the AWS CloudTrail User Guide', - 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsCloudTrailTrail', - 'Id': trailArn, - 'Partition': 'aws', - 'Region': awsRegion, - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-6', - 'NIST SP 800-53 SC-16', - 'NIST SP 800-53 SI-7', - 'AICPA TSC CC7.1', - 'ISO 27001:2013 A.12.2.1', - 'ISO 27001:2013 A.12.5.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3', - 'ISO 27001:2013 A.14.2.4' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/AWS_CodeBuild_Auditor.py b/auditors/AWS_CodeBuild_Auditor.py deleted file mode 100644 index 2af7448e..00000000 --- a/auditors/AWS_CodeBuild_Auditor.py +++ /dev/null @@ -1,775 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -codebuild = boto3.client("codebuild") -# create env vars -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through all CodeBuild projects and list their attributes -response = codebuild.list_projects() -allCodebuildProjects = response["projects"] -if allCodebuildProjects: - response = codebuild.batch_get_projects(names=allCodebuildProjects) - myCodeBuildProjects = response["projects"] -else: - response = "" - myCodeBuildProjects = "" - - -class ArtifactEncryptionCheck(Auditor): - def execute(self): - for projects in myCodeBuildProjects: - buildProjectName = str(projects["name"]) - buildProjectArn = str(projects["arn"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # check if this project supports artifacts - artifactCheck = str(projects["artifacts"]["type"]) - # skip projects without artifacts - if artifactCheck == "NO_ARTIFACTS": - print("No artifacts supported, skipping this check") - pass - else: - # check if encryption for artifacts is disabled - artifactEncryptionCheck = str( - projects["artifacts"]["encryptionDisabled"] - ) - if artifactEncryptionCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/unencrypted-artifacts", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[CodeBuild.1] CodeBuild projects should not have artifact encryption disabled", - "Description": "CodeBuild project " - + buildProjectName - + " has artifact encryption disabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your project should have artifact encryption enabled scroll down to item 8 in the Create a Build Project (Console) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/create-project.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/unencrypted-artifacts", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[CodeBuild.1] CodeBuild projects should not have artifact encryption disabled", - "Description": "CodeBuild project " - + buildProjectName - + " has artifact encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your project should have artifact encryption enabled scroll down to item 8 in the Create a Build Project (Console) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/create-project.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class InsecureSSLCheck(Auditor): - def execute(self): - for projects in myCodeBuildProjects: - buildProjectName = str(projects["name"]) - buildProjectArn = str(projects["arn"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # check if Insecure SSL is enabled for your Source - sourceInsecureSslCheck = str(projects["source"]["insecureSsl"]) - if sourceInsecureSslCheck != "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/insecure-ssl", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[CodeBuild.2] CodeBuild projects should not have insecure SSL configured", - "Description": "CodeBuild project " - + buildProjectName - + " has insecure SSL configured. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have insecure SSL configured refer to the Troubleshooting CodeBuild section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-self-signed-certificate", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/insecure-ssl", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[CodeBuild.2] CodeBuild projects should not have insecure SSL configured", - "Description": "CodeBuild project " - + buildProjectName - + " doesnt have insecure SSL configured.", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have insecure SSL configured refer to the Troubleshooting CodeBuild section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-self-signed-certificate", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class PlaintextENVvarCheck(Auditor): - def execute(self): - for projects in myCodeBuildProjects: - buildProjectName = str(projects["name"]) - buildProjectArn = str(projects["arn"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # check if this project has any env vars - envVarCheck = str(projects["environment"]["environmentVariables"]) - if envVarCheck == "[]": - print("No env vars, skipping this check") - pass - else: - # loop through env vars - codeBuildEnvVars = projects["environment"]["environmentVariables"] - for envvar in codeBuildEnvVars: - plaintextCheck = str(envvar["type"]) - # identify projects that don't use parameter store or AWS secrets manager - if plaintextCheck == "PLAINTEXT": - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/plaintext-env-vars", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - "Sensitive Data Identifications", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[CodeBuild.3] CodeBuild projects should not have plaintext environment variables", - "Description": "CodeBuild project " - + buildProjectName - + " contains plaintext environment variables. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your project should not contain plaintext environment variables refer to the Buildspec File Name and Storage Location section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": { - "Name": buildProjectName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/plaintext-env-vars", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - "Sensitive Data Identifications", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[CodeBuild.3] CodeBuild projects should not have plaintext environment variables", - "Description": "CodeBuild project " - + buildProjectName - + " does not contain plaintext environment variables.", - "Remediation": { - "Recommendation": { - "Text": "If your project should not contain plaintext environment variables refer to the Buildspec File Name and Storage Location section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": { - "Name": buildProjectName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class S3LoggingEncryptionCheck(Auditor): - def execute(self): - for projects in myCodeBuildProjects: - buildProjectName = str(projects["name"]) - buildProjectArn = str(projects["arn"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # check if this project disabled s3 log encryption - s3EncryptionCheck = str( - projects["logsConfig"]["s3Logs"]["encryptionDisabled"] - ) - if s3EncryptionCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/s3-encryption", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[CodeBuild.4] CodeBuild projects should not have S3 log encryption disabled", - "Description": "CodeBuild project " - + buildProjectName - + " has S3 log encryption disabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have S3 log encryption disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/s3-encryption", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[CodeBuild.4] CodeBuild projects should not have S3 log encryption disabled", - "Description": "CodeBuild project " - + buildProjectName - + " has S3 log encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have S3 log encryption disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class CloudwatchLoggingCheck(Auditor): - def execute(self): - for projects in myCodeBuildProjects: - buildProjectName = str(projects["name"]) - buildProjectArn = str(projects["arn"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # check if this project logs to cloudwatch - codeBuildLoggingCheck = str( - projects["logsConfig"]["cloudWatchLogs"]["status"] - ) - if codeBuildLoggingCheck != "ENABLED": - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/cloudwatch-logging", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[CodeBuild.5] CodeBuild projects should have CloudWatch logging enabled", - "Description": "CodeBuild project " - + buildProjectName - + " has CloudWatch logging disabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have CloudWatch logging disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": buildProjectArn + "/cloudwatch-logging", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": buildProjectArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[CodeBuild.5] CodeBuild projects should have CloudWatch logging enabled", - "Description": "CodeBuild project " - + buildProjectName - + " has CloudWatch logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your project should not have CloudWatch logging disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", - "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCodeBuildProject", - "Id": buildProjectArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCodeBuildProject": {"Name": buildProjectName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/AWS_DMS_Auditor.py b/auditors/AWS_DMS_Auditor.py deleted file mode 100644 index ade09a3a..00000000 --- a/auditors/AWS_DMS_Auditor.py +++ /dev/null @@ -1,387 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# create boto3 clients -sts = boto3.client('sts') -dms = boto3.client('dms') -# creat env vars -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] - -class dmsReplicationInstancePublicAccessCheck(Auditor): - def execute(self): - # loop through dms replication instances - response = dms.describe_replication_instances() - for repinstances in response['ReplicationInstances']: - dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) - dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) - publicAccessCheck = str(repinstances['PubliclyAccessible']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if publicAccessCheck == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[DMS.1] Database Migration Service instances should not be publicly accessible', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is publicly accessible. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'Public access on DMS instances cannot be changed, however, you can change the subnets that are in the subnet group that is associated with the replication instance to private subnets. For more informaton see the AWS Premium Support post How can I disable public access for an AWS DMS replication instance?.', - 'Url': 'https://aws.amazon.com/premiumsupport/knowledge-center/dms-disable-public-access/' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[DMS.1] Database Migration Service instances should not be publicly accessible', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is not publicly accessible.', - 'Remediation': { - 'Recommendation': { - 'Text': 'Public access on DMS instances cannot be changed, however, you can change the subnets that are in the subnet group that is associated with the replication instance to private subnets. For more informaton see the AWS Premium Support post How can I disable public access for an AWS DMS replication instance?.', - 'Url': 'https://aws.amazon.com/premiumsupport/knowledge-center/dms-disable-public-access/' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class dmsReplicationInstanceMultiAZCheck(Auditor): - def execute(self): - # loop through dms replication instances - response = dms.describe_replication_instances() - for repinstances in response['ReplicationInstances']: - dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) - dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) - mutltiAzCheck = str(repinstances['MultiAZ']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if mutltiAzCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-multi-az-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[DMS.2] Database Migration Service instances should have Multi-AZ configured', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' does not have Multi-AZ configured. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring DMS instances for Multi-AZ refer to the Working with an AWS DMS Replication Instance section of the AWS Database Migration Service User Guide', - 'Url': 'https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-multi-az-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[DMS.2] Database Migration Service instances should have Multi-AZ configured', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' has Multi-AZ configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring DMS instances for Multi-AZ refer to the Working with an AWS DMS Replication Instance section of the AWS Database Migration Service User Guide', - 'Url': 'https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class dmsReplicationInstanceMinorVersionUpdateCheck(Auditor): - def execute(self): - # loop through dms replication instances - response = dms.describe_replication_instances() - for repinstances in response['ReplicationInstances']: - dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) - dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) - minorVersionUpgradeCheck = str(repinstances['AutoMinorVersionUpgrade']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if minorVersionUpgradeCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-minor-version-auto-update-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[DMS.2] Database Migration Service instances should be configured to have minor version updates be automatically applied', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is not configured to have minor version updates be automatically applied. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring DMS instances for minor version updates refer to the AWS DMS Maintenance section of the AWS Database Migration Service User Guide', - 'Url': 'https://docs.amazonaws.cn/en_us/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.Maintenance' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.MA-1', - 'NIST SP 800-53 MA-2', - 'NIST SP 800-53 MA-3', - 'NIST SP 800-53 MA-5', - 'NIST SP 800-53 MA-6', - 'AICPA TSC CC8.1', - 'ISO 27001:2013 A.11.1.2', - 'ISO 27001:2013 A.11.2.4', - 'ISO 27001:2013 A.11.2.5', - 'ISO 27001:2013 A.11.2.6' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': dmsInstanceArn + '/dms-replication-instance-minor-version-auto-update-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': dmsInstanceArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[DMS.2] Database Migration Service instances should be configured to have minor version updates be automatically applied', - 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is configured to have minor version updates be automatically applied.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on configuring DMS instances for minor version updates refer to the AWS DMS Maintenance section of the AWS Database Migration Service User Guide', - 'Url': 'https://docs.amazonaws.cn/en_us/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.Maintenance' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsDmsReplicationInstance', - 'Id': dmsInstanceArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'replicationInstanceId': dmsInstanceId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.MA-1', - 'NIST SP 800-53 MA-2', - 'NIST SP 800-53 MA-3', - 'NIST SP 800-53 MA-5', - 'NIST SP 800-53 MA-6', - 'AICPA TSC CC8.1', - 'ISO 27001:2013 A.11.1.2', - 'ISO 27001:2013 A.11.2.4', - 'ISO 27001:2013 A.11.2.5', - 'ISO 27001:2013 A.11.2.6' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/AWS_Directory_Service_Auditor.py b/auditors/AWS_Directory_Service_Auditor.py deleted file mode 100644 index fe03a608..00000000 --- a/auditors/AWS_Directory_Service_Auditor.py +++ /dev/null @@ -1,291 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -ds = boto3.client('ds') -sts = boto3.client('sts') -# create account id & region variables -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# loop through Directory Service directories -# not to be confused with weird ass cloud directory -response = ds.describe_directories() -myDirectories = response['DirectoryDescriptions'] - -class DirectoryServiceRadiusCheck(Auditor): - def execute(self): - for directory in myDirectories: - directoryId = str(directory['DirectoryId']) - directoryArn = 'arn:aws:ds:' + awsRegion + ':' + awsAccountId + ':directory/' + directoryId - directoryName = str(directory['Name']) - directoryType = str(directory['Type']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if directoryType != 'SimpleAD': - try: - # this is a passing check - radiusCheck = str(directory['RadiusSettings']) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': directoryArn + '/directory-service-radius-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': directoryArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[DirectoryService.1] Supported directories should have RADIUS enabled for multi-factor authentication (MFA)', - 'Description': 'Directory ' + directoryName + ' has RADIUS enabled and likely supports MFA.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on directory MFA and configuring RADIUS refer to the Multi-factor Authentication Prerequisites section of the AWS Directory Service Administration Guide', - 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started_prereqs.html#prereq_mfa_ad' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': directoryArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'directoryName': directoryName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-6', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 AC-3', - 'NIST SP 800-53 AC-16', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-24', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 PE-2', - 'NIST SP 800-53 PS-3', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.7.1.1', - 'ISO 27001:2013 A.9.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': directoryArn + '/directory-service-radius-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': directoryArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[DirectoryService.1] Supported directories should have RADIUS enabled for multi-factor authentication (MFA)', - 'Description': 'Directory ' + directoryName + ' does not have RADIUS enabled and thus does not support MFA. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on directory MFA and configuring RADIUS refer to the Multi-factor Authentication Prerequisites section of the AWS Directory Service Administration Guide', - 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started_prereqs.html#prereq_mfa_ad' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': directoryArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'directoryName': directoryName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-6', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 AC-3', - 'NIST SP 800-53 AC-16', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-24', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 PE-2', - 'NIST SP 800-53 PS-3', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.7.1.1', - 'ISO 27001:2013 A.9.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print('SimpleAD does not support RADIUS, skipping') - pass - -class DirectoryServiceCloudwatchLogsCheck(Auditor): - def execute(self): - for directory in myDirectories: - directoryId = str(directory['DirectoryId']) - directoryArn = 'arn:aws:ds:' + awsRegion + ':' + awsAccountId + ':directory/' + directoryId - directoryName = str(directory['Name']) - response = ds.list_log_subscriptions(DirectoryId=directoryId) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(response['LogSubscriptions']) == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': directoryArn + '/directory-service-cloudwatch-logs-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': directoryArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[DirectoryService.2] Directories should have log forwarding enabled', - 'Description': 'Directory ' + directoryName + ' does not have log forwarding enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on directory log forwarding to CloudWatch Logs refer to the Enable Log Forwarding section of the AWS Directory Service Administration Guide', - 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_enable_log_forwarding.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': directoryArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'directoryName': directoryName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': directoryArn + '/directory-service-cloudwatch-logs-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': directoryArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[DirectoryService.2] Directories should have log forwarding enabled', - 'Description': 'Directory ' + directoryName + ' does not have log forwarding enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on directory log forwarding to CloudWatch Logs refer to the Enable Log Forwarding section of the AWS Directory Service Administration Guide', - 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_enable_log_forwarding.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': directoryArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'directoryName': directoryName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/AWS_Glue_Auditor.py b/auditors/AWS_Glue_Auditor.py deleted file mode 100644 index 37248827..00000000 --- a/auditors/AWS_Glue_Auditor.py +++ /dev/null @@ -1,814 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -glue = boto3.client('glue') -# create account id & region variables -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# loop through Glue Crawlers -try: - response = glue.list_crawlers() - myCrawlers = response['CrawlerNames'] -except Exception as e: - print(e) - -class CrawlerS3EncryptionCheck(Auditor): - def execute(self): - for crawlers in myCrawlers: - crawlerName = str(crawlers) - crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_crawler(Name=crawlerName) - crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) - try: - response = glue.get_security_configuration(Name=crawlerSecConfig) - s3EncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['S3Encryption'][0]['S3EncryptionMode']) - if s3EncryptionCheck == 'DISABLED': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-s3-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Glue.1] AWS Glue crawler security configurations should enable Amazon S3 encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables S3 encryption. When you are writing Amazon S3 data, you use either server-side encryption with Amazon S3 managed keys (SSE-S3) or server-side encryption with AWS KMS managed keys (SSE-KMS). Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-s3-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.1] AWS Glue crawler security configurations should enable Amazon S3 encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables S3 encryption.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - -class CrawlerCloudwatchEncryptionCheck(Auditor): - def execute(self): - for crawlers in myCrawlers: - crawlerName = str(crawlers) - crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_crawler(Name=crawlerName) - crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) - try: - response = glue.get_security_configuration(Name=crawlerSecConfig) - cwEncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['CloudWatchEncryption']['CloudWatchEncryptionMode']) - if cwEncryptionCheck == 'DISABLED': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-cloudwatch-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Glue.2] AWS Glue crawler security configurations should enable Amazon CloudWatch Logs encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables CloudWatch Logs encryption. Server-side (SSE-KMS) encryption is used to encrypt CloudWatch Logs. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-cloudwatch-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.2] AWS Glue crawler security configurations should enable Amazon CloudWatch Logs encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables CloudWatch Logs encryption.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - -class CrawlerJobBookmarkEncryptionCheck(Auditor): - def execute(self): - for crawlers in myCrawlers: - crawlerName = str(crawlers) - crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_crawler(Name=crawlerName) - crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) - try: - response = glue.get_security_configuration(Name=crawlerSecConfig) - jobBookmarkEncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['JobBookmarksEncryption']['JobBookmarksEncryptionMode']) - if jobBookmarkEncryptionCheck == 'DISABLED': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-job-bookmark-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Glue.3] AWS Glue crawler security configurations should enable job bookmark encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables job bookmark encryption. Client-side (CSE-KMS) encryption is used to encrypt job bookmarks, bookmark data is encrypted before it is sent to Amazon S3 for storage. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': crawlerArn + '/glue-crawler-job-bookmark-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': crawlerArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.3] AWS Glue crawler security configurations should enable job bookmark encryption', - 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables job bookmark encryption.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueCrawler', - 'Id': crawlerArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'crawlerName': crawlerName, - 'securityConfigurationId': crawlerSecConfig - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - -class GlueDataCatalogEncryptionCheck(Auditor): - def execute(self): - catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_data_catalog_encryption_settings() - catalogEncryptionCheck = str(response['DataCatalogEncryptionSettings']['EncryptionAtRest']['CatalogEncryptionMode']) - if catalogEncryptionCheck == 'DISABLED': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Glue.4] AWS Glue data catalogs should be encrypted at rest', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is not encrypted. You can enable or disable encryption settings for the entire Data Catalog. In the process, you specify an AWS KMS key that is automatically used when objects, such as tables, databases, partitions, table versions, connections and/or user-defined functions, are written to the Data Catalog. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog encryption refer to the Encrypting Your Data Catalog section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.4] AWS Glue data catalogs should be encrypted at rest', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is encrypted.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog encryption refer to the Encrypting Your Data Catalog section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class GlueDataCatalogPasswordEncryptionCheck(Auditor): - def execute(self): - catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_data_catalog_encryption_settings() - passwordEncryptionCheck = str(response['DataCatalogEncryptionSettings']['ConnectionPasswordEncryption']['ReturnConnectionPasswordEncrypted']) - if passwordEncryptionCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-password-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Glue.5] AWS Glue data catalogs should be configured to encrypt connection passwords', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is not configured to encrypt connection passwords. You can retrieve connection passwords in the AWS Glue Data Catalog by using the GetConnection and GetConnections API operations. These passwords are stored in the Data Catalog connection and are used when AWS Glue connects to a Java Database Connectivity (JDBC) data store. When the connection was created or updated, an option in the Data Catalog settings determined whether the password was encrypted. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog connection password encryption refer to the Encrypting Connection Passwords section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-connection-passwords.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-password-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.5] AWS Glue data catalogs should be configured to encrypt connection passwords', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is configured to encrypt connection passwords.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog connection password encryption refer to the Encrypting Connection Passwords section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-connection-passwords.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class GlueDataCatalogResourcePolicyCheck(Auditor): - def execute(self): - catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = glue.get_resource_policy() - policyHash = str(response['PolicyHash']) - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-resource-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Glue.6] AWS Glue data catalogs should enforce fine-grained access controls with a resource policy', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' uses a resource policy.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog resource policies refer to the AWS Glue Resource Policies for Access Control section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'policyHash': policyHash - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == 'An error occurred (EntityNotFoundException) when calling the GetResourcePolicy operation: Policy not found': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': catalogArn + '/glue-data-catalog-resource-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': catalogArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Glue.6] AWS Glue data catalogs should enforce fine-grained access controls with a resource policy', - 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' does not use a resource policy. AWS Glue supports using resource policies to control access to Data Catalog resources. These resources include databases, tables, connections, and user-defined functions, along with the Data Catalog APIs that interact with these resources. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on data catalog resource policies refer to the AWS Glue Resource Policies for Access Control section of the AWS Glue Developer Guide', - 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsGlueDataCatalog', - 'Id': catalogArn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) diff --git a/auditors/AWS_IAM_Auditor.py b/auditors/AWS_IAM_Auditor.py deleted file mode 100644 index 60f14f0b..00000000 --- a/auditors/AWS_IAM_Auditor.py +++ /dev/null @@ -1,1106 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -iam = boto3.client('iam') -# create account id & region variables -awsAccount = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -# loop through IAM users -try: - response = iam.list_users(MaxItems=1000) - allUsers = response['Users'] -except Exception as e: - print(e) - -class iamAccessKeyAgeCheck(Auditor): - def execute(self): - for users in allUsers: - userName = str(users['UserName']) - userArn = str(users['Arn']) - try: - response = iam.list_access_keys(UserName=userName) - for keys in response['AccessKeyMetadata']: - keyUserName = str(keys['UserName']) - keyId = str(keys['AccessKeyId']) - keyStatus = str(keys['Status']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if keyStatus == 'Active': - keyCreateDate = keys['CreateDate'] - todaysDatetime = datetime.datetime.now(datetime.timezone.utc) - keyAgeFinder = todaysDatetime - keyCreateDate - if keyAgeFinder <= datetime.timedelta(days=90): - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': keyUserName + keyId + '/iam-access-key-age-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn + keyId, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.1] IAM Access Keys should be rotated every 90 days', - 'Description': 'IAM access key ' + keyId + ' for user ' + keyUserName + ' is not over 90 days old.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on IAM access key rotation refer to the Rotating Access Keys section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_RotateAccessKey' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamAccessKey', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsIamAccessKey': { - 'PrincipalId': keyId, - 'PrincipalName': keyUserName, - 'Status': keyStatus - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': keyUserName + keyId + '/iam-access-key-age-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn + keyId, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[IAM.1] IAM Access Keys should be rotated every 90 days', - 'Description': 'IAM access key ' + keyId + ' for user ' + keyUserName + ' is over 90 days old. As a security best practice, AWS recommends that you regularly rotate (change) IAM user access keys. If your administrator granted you the necessary permissions, you can rotate your own access keys. Refer to the remediation section to remediate this behavior.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on IAM access key rotation refer to the Rotating Access Keys section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_RotateAccessKey' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamAccessKey', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'AwsIamAccessKey': { - 'PrincipalId': keyId, - 'PrincipalName': keyUserName, - 'Status': keyStatus - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - pass - except Exception as e: - print(e) - -class UserPermissionsBoundaryCheck(Auditor): - def execute(self): - for users in allUsers: - userName = str(users['UserName']) - userArn = str(users['Arn']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - permBoundaryArn = str(users['PermissionsBoundary']['PermissionsBoundaryArn']) - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-permissions-boundary-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.2] IAM users should have permissions boundaries attached', - 'Description': 'IAM user ' + userName + ' has a permissions boundary attached.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on permissions boundaries refer to the Permissions Boundaries for IAM Entities section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName, - 'permissionsBoundaryArn': permBoundaryArn - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-4', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 AC-3', - 'NIST SP 800-53 AC-5', - 'NIST SP 800-53 AC-6', - 'NIST SP 800-53 AC-14', - 'NIST SP 800-53 AC-16', - 'NIST SP 800-53 AC-24', - 'AICPA TSC CC6.3', - 'ISO 27001:2013 A.6.1.2', - 'ISO 27001:2013 A.9.1.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.4.1', - 'ISO 27001:2013 A.9.4.4', - 'ISO 27001:2013 A.9.4.5' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'PermissionsBoundary'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-permissions-boundary-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[IAM.2] IAM users should have permissions boundaries attached', - 'Description': 'IAM user ' + userName + ' does not have a permissions boundary attached. A permissions boundary is an advanced feature for using a managed policy to set the maximum permissions that an identity-based policy can grant to an IAM entity. A permissions boundary allows it to perform only the actions that are allowed by both its identity-based policies and its permissions boundaries. Refer to the remediation section to remediate this behavior.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on permissions boundaries refer to the Permissions Boundaries for IAM Entities section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-4', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 AC-3', - 'NIST SP 800-53 AC-5', - 'NIST SP 800-53 AC-6', - 'NIST SP 800-53 AC-14', - 'NIST SP 800-53 AC-16', - 'NIST SP 800-53 AC-24', - 'AICPA TSC CC6.3', - 'ISO 27001:2013 A.6.1.2', - 'ISO 27001:2013 A.9.1.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.4.1', - 'ISO 27001:2013 A.9.4.4', - 'ISO 27001:2013 A.9.4.5' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class UserMfaCheck(Auditor): - def execute(self): - for users in allUsers: - userName = str(users['UserName']) - userArn = str(users['Arn']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = iam.list_mfa_devices(UserName=userName) - if str(response['MFADevices']) == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-mfa-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[IAM.3] IAM users should have Multi-Factor Authentication (MFA) enabled', - 'Description': 'IAM user ' + userName + ' does not have MFA enabled. For increased security, AWS recommends that you configure multi-factor authentication (MFA) to help protect your AWS resources. Refer to the remediation section to remediate this behavior.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on MFA refer to the Using Multi-Factor Authentication (MFA) in AWS section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-mfa-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.3] IAM users should have Multi-Factor Authentication (MFA) enabled', - 'Description': 'IAM user ' + userName + ' has MFA enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on MFA refer to the Using Multi-Factor Authentication (MFA) in AWS section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class UserInlinePolicyCheck(Auditor): - def execute(self): - for users in allUsers: - userName = str(users['UserName']) - userArn = str(users['Arn']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = iam.list_user_policies(UserName=userName) - if str(response['PolicyNames']) != '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-attach-inline-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[IAM.4] IAM users should not have attached in-line policies', - 'Description': 'IAM user ' + userName + ' has an in-line policy attached. It is recommended that IAM policies be applied directly to groups and roles but not users. Refer to the remediation section to remediate this behavior.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-attach-inline-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.4] IAM users should not have attached in-line policies', - 'Description': 'IAM user ' + userName + ' does not have an in-line policy attached.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class UserDirectAttachedPolicyCheck(Auditor): - def execute(self): - for users in allUsers: - userName = str(users['UserName']) - userArn = str(users['Arn']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = iam.list_attached_user_policies(UserName=userName) - if str(response['AttachedPolicies']) != '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-attach-managed-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[IAM.5] IAM users should not have attached managed policies', - 'Description': 'IAM user ' + userName + ' has a managed policy attached. It is recommended that IAM policies be applied directly to groups and roles but not users. Refer to the remediation section to remediate this behavior.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': userArn + '/iam-user-attach-managed-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': userArn, - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.5] IAM users should not have attached managed policies', - 'Description': 'IAM user ' + userName + ' does not have a managed policy attached.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsIamUser', - 'Id': userArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'PrincipalName': userName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - -class CISawsFoundationsBenchmarkPWpolicyCheck(Auditor): - def execute(self): - try: - response = iam.get_account_password_policy() - pwPolicy = response['PasswordPolicy'] - minPwLength = int(pwPolicy['MinimumPasswordLength']) - symbolReq = str(pwPolicy['RequireSymbols']) - numberReq = str(pwPolicy['RequireNumbers']) - uppercaseReq = str(pwPolicy['RequireUppercaseCharacters']) - lowercaseReq = str(pwPolicy['RequireLowercaseCharacters']) - maxPwAge = int(pwPolicy['MaxPasswordAge']) - pwReuse = int(pwPolicy['PasswordReusePrevention']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if minPwLength >= 14 and maxPwAge <= 90 and pwReuse >= 24 and symbolReq == 'True' and numberReq == 'True' and uppercaseReq =='True' and lowercaseReq == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccount + '/cis-aws-foundations-benchmark-pw-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': awsAccount + 'iam-password-policy', - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.6] The IAM password policy should meet or exceed the AWS CIS Foundations Benchmark standard', - 'Description': 'The IAM password policy for account ' + awsAccount + ' meets or exceeds the AWS CIS Foundations Benchmark standard.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on the CIS AWS Foundations Benchmark standard for the password policy refer to the linked Standard', - 'Url': 'https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccount, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccount + '/cis-aws-foundations-benchmark-pw-policy-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': awsAccount + 'iam-password-policy', - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[IAM.6] The IAM password policy should meet or exceed the AWS CIS Foundations Benchmark standard', - 'Description': 'The IAM password policy for account ' + awsAccount + ' does not meet the AWS CIS Foundations Benchmark standard. Refer to the remediation instructions if this configuration is not intended.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on the CIS AWS Foundations Benchmark standard for the password policy refer to the linked Standard', - 'Url': 'https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccount, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - except Exception as e: - print(e) - -class ServerCertsCheck(Auditor): - def execute(self): - try: - response = iam.list_server_certificates() - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(response['ServerCertificateMetadataList']) != '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccount + '/server-x509-certs-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': awsAccount + 'server-cert', - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[IAM.7] There should not be any server certificates stored in AWS IAM', - 'Description': 'There are server certificates stored in AWS IAM for the account ' + awsAccount + '. ACM is the preferred tool to provision, manage, and deploy your server certificates. With ACM you can request a certificate or deploy an existing ACM or external certificate to AWS resources. Certificates provided by ACM are free and automatically renew. Refer to the remediation instructions if this configuration is not intended.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on server certificates refer to the Working with Server Certificates section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccount, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccount + '/server-x509-certs-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', - 'GeneratorId': awsAccount + 'server-cert', - 'AwsAccountId': awsAccount, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[IAM.7] There should not be any server certificates stored in AWS IAM', - 'Description': 'There are not server certificates stored in AWS IAM for the account ' + awsAccount + '.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on server certificates refer to the Working with Server Certificates section of the AWS IAM User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccount, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/AWS_Lambda_Auditor.py b/auditors/AWS_Lambda_Auditor.py deleted file mode 100644 index 7672e46b..00000000 --- a/auditors/AWS_Lambda_Auditor.py +++ /dev/null @@ -1,169 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from dateutil import parser -from auditors.Auditor import Auditor - -lambda_client = boto3.client("lambda") -cloudwatch = boto3.client("cloudwatch") -sts = boto3.client("sts") - - -class FunctionUnusedCheck(Auditor): - def execute(self): - response = lambda_client.list_functions() - functions = response["Functions"] - # create env vars - awsAccountId = sts.get_caller_identity()["Account"] - awsRegion = os.environ["AWS_REGION"] - for function in functions: - functionName = str(function["FunctionName"]) - lambdaArn = str(function["FunctionArn"]) - metricResponse = cloudwatch.get_metric_data( - MetricDataQueries=[ - { - "Id": "m1", - "MetricStat": { - "Metric": { - "Namespace": "AWS/Lambda", - "MetricName": "Invocations", - "Dimensions": [{"Name": "FunctionName", "Value": functionName},], - }, - "Period": 300, - "Stat": "Sum", - }, - } - ], - StartTime=datetime.datetime.now() - datetime.timedelta(days=30), - EndTime=datetime.datetime.now(), - ) - metrics = metricResponse["MetricDataResults"] - for metric in metrics: - modify_date = parser.parse(function["LastModified"]) - date_delta = datetime.datetime.now(datetime.timezone.utc) - modify_date - iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() - if len(metric["Values"]) > 0 or date_delta.days < 30: - finding = { - "SchemaVersion": "2018-10-08", - "Id": lambdaArn + "/lambda-function-unused-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": lambdaArn, - "AwsAccountId": awsAccountId, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", - "Description": "Lambda function " - + functionName - + " has been used or updated in the last 30 days.", - "Remediation": { - "Recommendation": { - "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", - "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsLambda", - "Id": lambdaArn, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": lambdaArn + "/lambda-function-unused-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": lambdaArn, - "AwsAccountId": awsAccountId, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", - "Description": "Lambda function " - + functionName - + " has not been used or updated in the last 30 days.", - "Remediation": { - "Recommendation": { - "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", - "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsLambda", - "Id": lambdaArn, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding diff --git a/auditors/AWS_License_Manager_Auditor.py b/auditors/AWS_License_Manager_Auditor.py deleted file mode 100644 index b6c693a8..00000000 --- a/auditors/AWS_License_Manager_Auditor.py +++ /dev/null @@ -1,162 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -licensemanager = boto3.client('license-manager') -# create account id & region variables -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] - -class LicenseManagerHardCountCheck(Auditor): - def execute(self): - try: - response = licensemanager.list_license_configurations() - lmCheck = str(response['LicenseConfigurations']) - if lmCheck == '[]': - pass - else: - myLiscMgrConfigs = response['LicenseConfigurations'] - for lmconfigs in myLiscMgrConfigs: - liscConfigArn = str(lmconfigs['LicenseConfigurationArn']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = licensemanager.get_license_configuration(LicenseConfigurationArn=liscConfigArn) - liscConfigId = str(response['LicenseConfigurationId']) - liscConfigName = str(response['Name']) - hardLimitCheck = str(response['LicenseCountHardLimit']) - if hardLimitCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': liscConfigArn + '/license-manager-enforce-hard-limit-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': liscConfigArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[LicenseManager.1] License Manager license configurations should be configured to enforce a hard limit', - 'Description': 'License Manager license configuration ' + liscConfigName + ' does not enforce a hard limit. Enforcing a hard limit prevents new instances from being created that if you have already provisioned all available licenses. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on hard limits refer to the License Configuration Parameters and Rules section of the AWS License Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/license-manager/latest/userguide/config-overview.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': liscConfigArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'licenseConfigurationId': liscConfigId, - 'licenseConfigurationName': liscConfigName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.AM-2', - 'NIST SP 800-53 CM-8', - 'NIST SP 800-53 PM-5', - 'AICPA TSC CC3.2', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.1.1', - 'ISO 27001:2013 A.8.1.2', - 'ISO 27001:2013 A.12.5.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': liscConfigArn + '/license-manager-enforce-hard-limit-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': liscConfigArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[LicenseManager.1] License Manager license configurations should be configured to enforce a hard limit', - 'Description': 'License Manager license configuration ' + liscConfigName + ' enforces a hard limit.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For information on hard limits refer to the License Configuration Parameters and Rules section of the AWS License Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/license-manager/latest/userguide/config-overview.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': liscConfigArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'licenseConfigurationId': liscConfigId, - 'licenseConfigurationName': liscConfigName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.AM-2', - 'NIST SP 800-53 CM-8', - 'NIST SP 800-53 PM-5', - 'AICPA TSC CC3.2', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.1.1', - 'ISO 27001:2013 A.8.1.2', - 'ISO 27001:2013 A.12.5.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) diff --git a/auditors/AWS_Secrets_Manager_Auditor.py b/auditors/AWS_Secrets_Manager_Auditor.py deleted file mode 100644 index a5d4e3c3..00000000 --- a/auditors/AWS_Secrets_Manager_Auditor.py +++ /dev/null @@ -1,329 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -secretsmanager = boto3.client('secretsmanager') -# create env vars -awsRegion = os.environ['AWS_REGION'] -awsAccountId = sts.get_caller_identity()['Account'] -# loop through all secrets -response = secretsmanager.list_secrets(MaxResults=100) -myAsmSecrets = response['SecretList'] - -class SecretAgeCheck(Auditor): - def execute(self): - for secrets in myAsmSecrets: - secretArn = str(secrets['ARN']) - secretName = str(secrets['Name']) - lastChangedDate = (secrets['LastChangedDate']) - todaysDatetime = datetime.datetime.now(datetime.timezone.utc) - secretAgeFinder = todaysDatetime - lastChangedDate - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if secretAgeFinder >= datetime.timedelta(days=90): - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': secretArn + '/secrets-manager-age-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': secretArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SecretsManager.1] Secrets over 90 days old should be rotated', - 'Description': secretName + ' is over 90 days old and should be rotated. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': secretArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'secretName': secretName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': secretArn + '/secrets-manager-age-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': secretArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SecretsManager.1] Secrets over 90 days old should be rotated', - 'Description': secretName + ' is over 90 days old and should be rotated.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': secretArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'secretName': secretName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class SecretChangedInLast90Check(Auditor): - def execute(self): - for secrets in myAsmSecrets: - secretArn = str(secrets['ARN']) - secretName = str(secrets['Name']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - rotationCheck = str(secrets['RotationEnabled']) - print(rotationCheck) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': secretArn + '/secrets-manager-rotation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': secretArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SecretsManager.2] Secrets should have automatic rotation configured', - 'Description': secretName + ' has automatic rotation configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': secretArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'secretName': secretName } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': secretArn + '/secrets-manager-rotation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': secretArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SecretsManager.2] Secrets should have automatic rotation configured', - 'Description': secretName + ' does not have automatic rotation configured. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', - 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': secretArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'secretName': secretName } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-1', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-2', - 'NIST SP 800-53 IA-1', - 'NIST SP 800-53 IA-2', - 'NIST SP 800-53 IA-3', - 'NIST SP 800-53 IA-4', - 'NIST SP 800-53 IA-5', - 'NIST SP 800-53 IA-6', - 'NIST SP 800-53 IA-7', - 'NIST SP 800-53 IA-8', - 'NIST SP 800-53 IA-9', - 'NIST SP 800-53 IA-10', - 'NIST SP 800-53 IA-11', - 'AICPA TSC CC6.1', - 'AICPA TSC CC6.2', - 'ISO 27001:2013 A.9.2.1', - 'ISO 27001:2013 A.9.2.2', - 'ISO 27001:2013 A.9.2.3', - 'ISO 27001:2013 A.9.2.4', - 'ISO 27001:2013 A.9.2.6', - 'ISO 27001:2013 A.9.3.1', - 'ISO 27001:2013 A.9.4.2', - 'ISO 27001:2013 A.9.4.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding diff --git a/auditors/AWS_Security_Hub_Auditor.py b/auditors/AWS_Security_Hub_Auditor.py deleted file mode 100644 index 1be88fac..00000000 --- a/auditors/AWS_Security_Hub_Auditor.py +++ /dev/null @@ -1,170 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# import boto3 clients -securityhub = boto3.client('securityhub') -sts = boto3.client('sts') -# create aws account ID variable for filters -awsAccountId = sts.get_caller_identity()['Account'] -awsRegion = os.environ['AWS_REGION'] -try: - # look for active high or critical findings from AWS products - getFindings = securityhub.get_findings( - Filters={ - # look for findings that belong to current account - # will help deconflict checks run in a master account - 'AwsAccountId': [ - { - 'Value': awsAccountId, - 'Comparison': 'EQUALS' - } - ], - # look for high or critical severity findings - 'SeverityLabel': [ - { - 'Value': 'HIGH', - 'Comparison': 'EQUALS' - }, - { - 'Value': 'CRITICAL', - 'Comparison': 'EQUALS' - } - ], - # look for AWS security hub integrations - # company can be AWS or Amazon depending on service - 'CompanyName': [ - { - 'Value': 'AWS', - 'Comparison': 'EQUALS' - }, - { - 'Value': 'Amazon', - 'Comparison': 'EQUALS' - } - ], - # check for Active Records - 'RecordState': [ - { - 'Value': 'ACTIVE', - 'Comparison': 'EQUALS' - } - ] - }, - SortCriteria=[ - { - 'Field': 'SeverityLabel', - 'SortOrder': 'asc' - } - ], - MaxResults=100 - ) -except Exception as e: - print(e) - -class HighCriticalFindings(Auditor): - def execute(self): - generatorId = str(getFindings['ResponseMetadata']['RequestId']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(getFindings['Findings']) == '[]': - finding={ - 'SchemaVersion': '2018-10-08', - 'Id': 'high-critical-findings-located/' + awsAccountId, - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorId, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Title': '[SecurityHub.1] Security Hub should not have active high or critical severity findings from AWS services', - 'Description': 'High or critical findings were not found in the Security Hub hub for AWS account ' + awsAccountId, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': 'high-critical-findings-located/' + awsAccountId, - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorId, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { - 'Label': 'CRITICAL' - }, - 'Title': '[SecurityHub.1] Security Hub should not have active high or critical severity findings from AWS services', - 'Description': 'High or critical findings were found in the Security Hub hub for AWS account ' + awsAccountId, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding diff --git a/auditors/AWS_Security_Services_Auditor.py b/auditors/AWS_Security_Services_Auditor.py deleted file mode 100644 index d3143ad0..00000000 --- a/auditors/AWS_Security_Services_Auditor.py +++ /dev/null @@ -1,369 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import uuid -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -accessanalyzer = boto3.client('accessanalyzer') -guardduty = boto3.client('guardduty') -detective = boto3.client('detective') -# create env vars -awsRegion = os.environ['AWS_REGION'] -awsAccountId = sts.get_caller_identity()['Account'] - -class iamAccessAnalyzerDetectorCheck(Auditor): - def execute(self): - response = accessanalyzer.list_analyzers() - iamAccessAnalyzerCheck = str(response['analyzers']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - # unique ID - generatorUuid = str(uuid.uuid4()) - if iamAccessAnalyzerCheck == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-iaa-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SecSvcs.1] Amazon IAM Access Analyzer should be enabled', - 'Description': 'Amazon IAM Access Analyzer is not enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If IAM Access Analyzer should be enabled refer to the Enabling Access Analyzer section of the AWS Identity and Access Management User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html#access-analyzer-enabling' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-iaa-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SecSvcs.1] Amazon IAM Access Analyzer should be enabled', - 'Description': 'Amazon IAM Access Analyzer is enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If IAM Access Analyzer should be enabled refer to the Enabling Access Analyzer section of the AWS Identity and Access Management User Guide', - 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html#access-analyzer-enabling' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class GuardDutyDetectorCheck(Auditor): - def execute(self): - response = guardduty.list_detectors() - guarddutyDetectorCheck = str(response['DetectorIds']) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - # unique ID - generatorUuid = str(uuid.uuid4()) - if guarddutyDetectorCheck == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-guardduty-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SecSvcs.2] Amazon GuardDuty should be enabled', - 'Description': 'Amazon GuardDuty is not enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If GuardDuty should be enabled refer to the Setting Up GuardDuty section of the Amazon GuardDuty User Guide', - 'Url': 'https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-guardduty-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SecSvcs.2] Amazon GuardDuty should be enabled', - 'Description': 'Amazon GuardDuty is not enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If GuardDuty should be enabled refer to the Setting Up GuardDuty section of the Amazon GuardDuty User Guide', - 'Url': 'https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class DetectiveGraphCheck(Auditor): - def execute(self): - try: - response = detective.list_graphs(MaxResults=200) - # ISO Time - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - # unique ID - generatorUuid = str(uuid.uuid4()) - if str(response['GraphList']) == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-detective-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SecSvcs.3] Amazon Detective should be enabled', - 'Description': 'Amazon Detective is not enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'If Detective should be enabled refer to the Setting up Amazon Detective section of the Amazon Detective Administration Guide', - 'Url': 'https://docs.aws.amazon.com/detective/latest/adminguide/detective-setup.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/security-services-detective-enabled-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': generatorUuid, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SecSvcs.3] Amazon Detective should be enabled', - 'Description': 'Amazon Detective is enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'If Detective should be enabled refer to the Setting up Amazon Detective section of the Amazon Detective Administration Guide', - 'Url': 'https://docs.aws.amazon.com/detective/latest/adminguide/detective-setup.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-2', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 SI-4', - 'AICPA TSC 7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.1', - 'ISO 27001:2013 A.16.1.4' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_APIGW_Auditor.py b/auditors/Amazon_APIGW_Auditor.py deleted file mode 100644 index dff090e0..00000000 --- a/auditors/Amazon_APIGW_Auditor.py +++ /dev/null @@ -1,1082 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -apigateway = boto3.client("apigateway") -sts = boto3.client("sts") - -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through API Gateway rest apis -response = apigateway.get_rest_apis(limit=500) -myRestApis = response["items"] - - -class ApiGatewayStageMetricsEnabledCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - # is is possible methodSettings is empty indicating metrics are not enabled - try: - metricsCheck = str(apistages["methodSettings"]["*/*"]["metricsEnabled"]) - except KeyError: - metricsCheck = "False" - if metricsCheck == "False": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-metrics-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " does not have CloudWatch metrics enabled. You can monitor API execution by using CloudWatch, which collects and processes raw data from API Gateway into readable, near-real-time metrics. These statistics are recorded for a period of 15 months so you can access historical information and gain a better perspective on how your web application or service is performing. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-metrics-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " has CloudWatch metrics enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class ApiGatewayStageLoggingCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - # it is possible for methodSettings to be empty indicating logging is Off - try: - loggingCheck = str(apistages["methodSettings"]["*/*"]["loggingLevel"]) - except KeyError: - loggingCheck = "OFF" - if loggingCheck == "OFF": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-api-logging-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " does not have CloudWatch API Logging enabled. To help debug issues related to request execution or client access to your API, you can enable Amazon CloudWatch Logs to log API calls. The logged data includes errors or execution traces (such as request or response parameter values or payloads), data used by Lambda authorizers (formerly known as custom authorizers), whether API keys are required, whether usage plans are enabled, and so on. Refer to the remediation instructions if this configuration is not intended.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-api-logging-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " has CloudWatch API Logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class ApiGatewayStageCacheingEnabledCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - # it is possible for methodSettings to be empty which indicated caching is not enabled - try: - cachingCheck = str(apistages["methodSettings"]["*/*"]["cachingEnabled"]) - except KeyError: - cachingCheck = "False" - if cachingCheck == "False": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-caching-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " does not have Caching enabled. You can enable API caching in Amazon API Gateway to cache your endpoints responses. With caching, you can reduce the number of calls made to your endpoint and also improve the latency of requests to your API. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-caching-enabled-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " has Caching enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class ApiGatewayStageCacheEncryptionCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - try: - cachingEncryptionCheck = str( - apistages["methodSettings"]["*/*"]["cacheDataEncrypted"] - ) - except KeyError: - cachingEncryptionCheck = "False" - if cachingEncryptionCheck == "False": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-cache-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " does not have cache encryption enabled. If you choose to enable caching for a REST API, you can enable cache encryption. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-cache-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " has cache encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class ApiGatewayStageXrayTracingCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - xrayTracingCheck = str(apistages["tracingEnabled"]) - if xrayTracingCheck == "False": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-xray-tracing-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " does not have tracing enabled. Because X-Ray gives you an end-to-end view of an entire request, you can analyze latencies in your APIs and their backend services. You can use an X-Ray service map to view the latency of an entire request and that of the downstream services that are integrated with X-Ray. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-xray-tracing-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " has tracing enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class ApiGatewayStageWafCheckCheck(Auditor): - def execute(self): - for restapi in myRestApis: - apiGwApiId = str(restapi["id"]) - apiGwApiName = str(restapi["name"]) - response = apigateway.get_stages(restApiId=apiGwApiId) - for apistages in response["item"]: - apiStageName = str(apistages["stageName"]) - apiStageDeploymentId = str(apistages["deploymentId"]) - apiStageArn = ( - "arn:aws:apigateway:" - + awsRegion - + "::/restapis/" - + apiGwApiId - + "/stages/" - + apiStageName - ) - try: - wafCheck = str(apistages["webAclArn"]) - # this is a passing check - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-waf-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " is protected by an AWS WAF Web ACL.", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - if str(e) == "'webAclArn'": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": apiStageArn + "/apigateway-stage-waf-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": apiStageArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", - "Description": "API Gateway stage " - + apiStageName - + " for Rest API " - + apiGwApiName - + " is not protected by an AWS WAF Web ACL. You can use AWS WAF to protect your API Gateway API from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect API availability and performance, compromise security, or consume excessive resources. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", - "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsApiGatewayRestApi", - "Id": apiStageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "deploymentId": apiStageDeploymentId, - "stageName": apiStageName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - print(e) diff --git a/auditors/Amazon_AppStream_Auditor.py b/auditors/Amazon_AppStream_Auditor.py deleted file mode 100644 index 9af82f96..00000000 --- a/auditors/Amazon_AppStream_Auditor.py +++ /dev/null @@ -1,542 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -appstream = boto3.client("appstream") -sts = boto3.client("sts") -# create account id & region variables -awsAccount = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] - - -class DefaultInternetAccessCheck(Auditor): - def execute(self): - # loop through AppStream 2.0 fleets - response = appstream.describe_fleets() - myAppstreamFleets = response["Fleets"] - for fleet in myAppstreamFleets: - iso8601Time = ( - datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - ) - fleetArn = str(fleet["Arn"]) - fleetName = str(fleet["DisplayName"]) - # find fleets that are configured to provide default internet access - defaultInternetAccessCheck = str(fleet["EnableDefaultInternetAccess"]) - if defaultInternetAccessCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": fleetArn + "/appstream-default-internet-access", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": fleetArn, - "AwsAccountId": awsAccount, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[AppStream.1] AppStream 2.0 fleets should not provide default internet access", - "Description": "AppStream 2.0 fleet " - + fleetName - + " is configured to provide default internet access. If you use the Default Internet Access option for enabling internet access, the NAT configuration is not limited to 100 fleet instances. If your deployment must support more than 100 concurrent users, use this configuration. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your fleet should not have default internet access refer to the instructions in the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/internet-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAppStreamFleet", - "Id": fleetArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"fleetName": fleetName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": fleetArn + "/appstream-default-internet-access", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": fleetArn, - "AwsAccountId": awsAccount, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AppStream.1] AppStream 2.0 fleets should not provide default internet access", - "Description": "AppStream 2.0 fleet " - + fleetName - + " is not configured to provide default internet access.", - "Remediation": { - "Recommendation": { - "Text": "If your fleet should not have default internet access refer to the instructions in the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/internet-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAppStreamFleet", - "Id": fleetArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"fleetName": fleetName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class PublicImageCheck(Auditor): - """Check for appstream images marked public - - TODO: Right now, this check is returning all public images including what appear - to be globally public images. My best guess right now is that we could look at - the arn of public images that don't have an accountId in the arn and ignore those. - """ - - def execute(self): - # loop through AppStream 2.0 images - response = appstream.describe_images(Type="PUBLIC", MaxResults=25) - myAppstreamImages = response["Images"] - for images in myAppstreamImages: - imageName = str(images["Name"]) - imageArn = str(images["Arn"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - ) - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": imageArn + "/appstream-public-image", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": imageArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[AppStream.2] AppStream 2.0 images you build should not be publicly accessible", - "Description": "AppStream 2.0 image " - + imageName - + " is publicly accessible. Permissions set on images that are shared with you may limit what you can do with those images. Refer to the remediation instructions if this configuration is not intended. Note that AWS managed AppStream 2.0 images will always be publicly accessible", - "Remediation": { - "Recommendation": { - "Text": "If your image should not be publicly accessible refer to the instructions in the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/administer-images.html#stop-sharing-image-with-all-accounts", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": imageArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"Image Name": imageName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class CompromiseAppstreamUserCheck(Auditor): - def execute(self): - # loop through AppStream 2.0 users - response = appstream.describe_users(AuthenticationType="USERPOOL") - myAppStreamUsers = response["Users"] - for users in myAppStreamUsers: - userArn = str(users["Arn"]) - userName = str(users["UserName"]) - userStatus = str(users["Status"]) - iso8601Time = ( - datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - ) - if userStatus == "COMPROMISED": - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": userArn + "/appstream-compromised-user", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Unusual Behaviors/User", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[AppStream.3] AppStream 2.0 users should be monitored for signs of compromise", - "Description": "AppStream 2.0 user " - + userName - + " is compromised. COMPROMISED – The user is disabled because of a potential security threat. Refer to the remediation instructions for information on how to remove them", - "Remediation": { - "Recommendation": { - "Text": "To disable and remove compromised users refer to the instructions in the User Pool Administration section of the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/user-pool-admin.html#user-pool-admin-disabling", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": userArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"userName": userName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-3", - "NIST CSF DE.CM-7", - "NIST SP 800-53 AU-12", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 CM-3", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PE-3", - "NIST SP 800-53 PE-6", - "NIST SP 800-53 PE-20", - "NIST SP 800-53 PM-12", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 RA-3", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5" "AICPA TSC CC3.2", - "AICPA TSC CC7.2", - "ISO 27001:2013 Clause 6.1.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.14.2.7", - "ISO 27001:2013 A.15.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": userArn + "/appstream-compromised-user", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Unusual Behaviors/User", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AppStream.3] AppStream 2.0 users should be monitored for signs of compromise", - "Description": "AppStream 2.0 user " + userName + " is not compromised.", - "Remediation": { - "Recommendation": { - "Text": "To disable and remove compromised users refer to the instructions in the User Pool Administration section of the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/user-pool-admin.html#user-pool-admin-disabling", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": userArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"userName": userName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-3", - "NIST CSF DE.CM-7", - "NIST SP 800-53 AU-12", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 CM-3", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PE-3", - "NIST SP 800-53 PE-6", - "NIST SP 800-53 PE-20", - "NIST SP 800-53 PM-12", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 RA-3", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5" "AICPA TSC CC3.2", - "AICPA TSC CC7.2", - "ISO 27001:2013 Clause 6.1.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.14.2.7", - "ISO 27001:2013 A.15.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class UserpoolAuthCheck(Auditor): - def execute(self): - # loop through AppStream 2.0 users - response = appstream.describe_users(AuthenticationType="USERPOOL") - myAppStreamUsers = response["Users"] - for users in myAppStreamUsers: - iso8601Time = ( - datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - ) - userArn = str(users["Arn"]) - userName = str(users["UserName"]) - # find users that do not auth with SAML - # basic auth & API access will show as non-compliant - userAuthType = str(users["AuthenticationType"]) - if userAuthType != "SAML": - finding = { - "SchemaVersion": "2018-10-08", - "Id": userArn + "/appstream-compromised-user", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userArn, - "AwsAccountId": awsAccount, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[AppStream.4] AppStream 2.0 users should be configured to authenticate using SAML", - "Description": "AppStream 2.0 user " - + userName - + " is not configured to authenticate using SAML. This feature offers your users the convenience of one-click access to their AppStream 2.0 applications using their existing identity credentials. You also have the security benefit of identity authentication by your IdP. By using your IdP, you can control which users have access to a particular AppStream 2.0 stack. Refer to the remediation instructions for information on how to remove them", - "Remediation": { - "Recommendation": { - "Text": "For information on setting up SAML refer to the Setting Up SAML section of the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/external-identity-providers-setting-up-saml.html#external-identity-providers-create-saml-provider", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": userArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"userName": userName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": userArn + "/appstream-compromised-user", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userArn, - "AwsAccountId": awsAccount, - "Types": ["Software and Configuration Checks/AWS Security Best Practices"], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AppStream.4] AppStream 2.0 users should be configured to authenticate using SAML", - "Description": "AppStream 2.0 user " - + userName - + " is configured to authenticate using SAML.", - "Remediation": { - "Recommendation": { - "Text": "For information on setting up SAML refer to the Setting Up SAML section of the Amazon AppStream 2.0 Administration Guide", - "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/external-identity-providers-setting-up-saml.html#external-identity-providers-create-saml-provider", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": userArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"userName": userName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_CognitoIdP_Auditor.py b/auditors/Amazon_CognitoIdP_Auditor.py deleted file mode 100644 index cc626f66..00000000 --- a/auditors/Amazon_CognitoIdP_Auditor.py +++ /dev/null @@ -1,541 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -cognitoidp = boto3.client("cognito-idp") -sts = boto3.client("sts") -# create account id & region variables -awsAccount = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] - - -class CognitoidpCisPasswordCheck(Auditor): - def execute(self): - response = cognitoidp.list_user_pools(MaxResults=60) - myCognitoUserPools = response["UserPools"] - for userpools in myCognitoUserPools: - userPoolId = str(userpools["Id"]) - response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) - userPoolArn = str(response["UserPool"]["Arn"]) - userPoolId = str(response["UserPool"]["Id"]) - cognitoPwPolicy = response["UserPool"]["Policies"]["PasswordPolicy"] - minLengthCheck = int(cognitoPwPolicy["MinimumLength"]) - uppercaseCheck = str(cognitoPwPolicy["RequireUppercase"]) - lowercaseCheck = str(cognitoPwPolicy["RequireLowercase"]) - numberCheck = str(cognitoPwPolicy["RequireNumbers"]) - symbolCheck = str(cognitoPwPolicy["RequireSymbols"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - minLengthCheck >= 14 - and uppercaseCheck == "True" - and lowercaseCheck == "True" - and numberCheck == "True" - and symbolCheck == "True" - ): - # this is a passing check - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-password-policy", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Cognito-IdP.1] Cognito user pools should have a password policy that meets or exceed AWS CIS Foundations Benchmark standards", - "Description": "Cognito user pool " - + userPoolArn - + " meets the password guidelines.", - "Remediation": { - "Recommendation": { - "Text": "To ensure you Cognito user pools have a password policy that meets or exceed AWS CIS Foundations Benchmark standards refer to the Adding User Pool Password Requirements section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-password-policy", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Cognito-IdP.1] Cognito user pools should have a password policy that meets or exceed AWS CIS Foundations Benchmark standards", - "Description": "Cognito user pool " - + userPoolArn - + " does not meet the password guidelines. Password policies, in part, enforce password complexity requirements, setting a password complexity policy increases account resiliency against brute force login attempts. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "To ensure you Cognito user pools have a password policy that meets or exceed AWS CIS Foundations Benchmark standards refer to the Adding User Pool Password Requirements section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class CognitoidpTempPasswordCheck(Auditor): - def execute(self): - response = cognitoidp.list_user_pools(MaxResults=60) - myCognitoUserPools = response["UserPools"] - for userpools in myCognitoUserPools: - userPoolId = str(userpools["Id"]) - response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) - userPoolArn = str(response["UserPool"]["Arn"]) - userPoolId = str(response["UserPool"]["Id"]) - cognitoPwPolicy = response["UserPool"]["Policies"]["PasswordPolicy"] - tempPwValidityCheck = int(cognitoPwPolicy["TemporaryPasswordValidityDays"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if tempPwValidityCheck > 1: - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-temp-password-life", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Cognito-IdP.2] Cognito user pools should not allow temporary passwords to stay valid beyond 24 hours", - "Description": "Cognito user pool " - + userPoolArn - + " allows temporary passwords to stay valid beyond 24 hours. Password policies, in part, enforce password complexity requirements, setting a password complexity policy increases account resiliency against brute force login attempts. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "To modify your Cognito user pool temporary password policy refer to the Authentication Flow for Users Created by Administrators or Developers section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-temp-password-life", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Cognito-IdP.2] Cognito user pools should not allow temporary passwords to stay valid beyond 24 hours", - "Description": "Cognito user pool " - + userPoolArn - + " does not allow temporary passwords to stay valid beyond 24 hours.", - "Remediation": { - "Recommendation": { - "Text": "To modify your Cognito user pool temporary password policy refer to the Authentication Flow for Users Created by Administrators or Developers section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class CognitoidpMfaCheck(Auditor): - def execute(self): - response = cognitoidp.list_user_pools(MaxResults=60) - myCognitoUserPools = response["UserPools"] - for userpools in myCognitoUserPools: - userPoolId = str(userpools["Id"]) - response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) - userPoolArn = str(response["UserPool"]["Arn"]) - userPoolId = str(response["UserPool"]["Id"]) - mfaCheck = str(response["UserPool"]["MfaConfiguration"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if mfaCheck != "ON": - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-mfa", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Cognito-IdP.3] Cognito user pools should enforce multi factor authentication (MFA)", - "Description": "Cognito user pool " - + userPoolArn - + " does not enforce multi factor authentication (MFA). AWS recommends enabling MFA for all accounts that have a console password. Enabling MFA provides increased security for console access because it requires the authenticating principal to possess a device that emits a time-sensitive key and have knowledge of a credential. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "To ensure you Cognito user pools enforce MFA refer to the Adding Multi-Factor Authentication (MFA) to a User Pool section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": userPoolArn + "/cognito-user-pool-mfa", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": userPoolId, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Cognito-IdP.3] Cognito user pools should enforce multi factor authentication (MFA)", - "Description": "Cognito user pool " - + userPoolArn - + " enforces multi factor authentication (MFA).", - "Remediation": { - "Recommendation": { - "Text": "To ensure you Cognito user pools enforce MFA refer to the Adding Multi-Factor Authentication (MFA) to a User Pool section of the Amazon Cognito Developer Guide", - "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCognitoUserPool", - "Id": userPoolArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"UserPoolId": userPoolId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-1", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-3", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-6", - "NIST SP 800-53 IA-7", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 IA-9", - "NIST SP 800-53 IA-10", - "NIST SP 800-53 IA-11", - "AICPA TSC CC6.1", - "AICPA TSC CC6.2", - "ISO 27001:2013 A.9.2.1", - "ISO 27001:2013 A.9.2.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.2.4", - "ISO 27001:2013 A.9.2.6", - "ISO 27001:2013 A.9.3.1", - "ISO 27001:2013 A.9.4.2", - "ISO 27001:2013 A.9.4.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_DocumentDB_Auditor.py b/auditors/Amazon_DocumentDB_Auditor.py deleted file mode 100644 index 55e8d53a..00000000 --- a/auditors/Amazon_DocumentDB_Auditor.py +++ /dev/null @@ -1,1330 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -documentdb = boto3.client("docdb") -sts = boto3.client("sts") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# find document db instances -response = documentdb.describe_db_instances( - Filters=[{"Name": "engine", "Values": ["docdb"]}], MaxRecords=100 -) -myDocDbs = response["DBInstances"] - - -class DocdbPublic_Instance_Check(Auditor): - def execute(self): - for docdb in myDocDbs: - docdbId = str(docdb["DBInstanceIdentifier"]) - docdbArn = str(docdb["DBInstanceArn"]) - publicAccessCheck = str(docdb["PubliclyAccessible"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if publicAccessCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-public-access", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[DocDb.1] DocumentDB instances should not be exposed to the public", - "Description": "DocumentDB instance " - + docdbId - + " is exposed to the public. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB is not intended to be public refer to the Connecting to an Amazon DocumentDB Cluster from Outside an Amazon VPC section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/connect-from-outside-a-vpc.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-public-access", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.1] DocumentDB instances should not be exposed to the public", - "Description": "DocumentDB instance " - + docdbId - + " is not exposed to the public.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB is not intended to be public refer to the Connecting to an Amazon DocumentDB Cluster from Outside an Amazon VPC section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/connect-from-outside-a-vpc.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class DocdbInstanceEncryptionCheck(Auditor): - def execute(self): - for docdb in myDocDbs: - docdbId = str(docdb["DBInstanceIdentifier"]) - docdbArn = str(docdb["DBInstanceArn"]) - encryptionCheck = str(docdb["StorageEncrypted"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if encryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[DocDb.2] DocumentDB instances should be encrypted", - "Description": "DocumentDB instance " - + docdbId - + " is not encrypted. You encrypt data at rest in your Amazon DocumentDB cluster by specifying the storage encryption option when you create your cluster. Storage encryption is enabled cluster-wide and is applied to all instances, including the primary instance and any replicas. It is also applied to your cluster’s storage volume, data, indexes, logs, automated backups, and snapshots. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB is not intended to be unencrypted refer to Encrypting Amazon DocumentDB Data at Rest in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.2] DocumentDB instances should be encrypted", - "Description": "DocumentDB instance " + docdbId + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB is not intended to be unencrypted refer to Encrypting Amazon DocumentDB Data at Rest in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class DocdbInstanceAuditLoggingCheck(Auditor): - def execute(self): - for docdb in myDocDbs: - docdbId = str(docdb["DBInstanceIdentifier"]) - docdbArn = str(docdb["DBInstanceArn"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - logCheck = str(docdb["EnabledCloudwatchLogsExports"]) - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-instance-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.3] DocumentDB instances should have audit logging configured", - "Description": "DocumentDB instance " - + docdbId - + " has audit logging configured.", - "Remediation": { - "Recommendation": { - "Text": "For information on DocumentDB audit logging refer to the Auditing Amazon DocumentDB Events section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbArn + "/docdb-instance-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[DocDb.3] DocumentDB instances should have audit logging configured", - "Description": "DocumentDB instance " - + docdbId - + " does not have audit logging configured. Profiler is useful for monitoring the slowest operations on your cluster to help you improve individual query performance and overall cluster performance. When enabled, operations are logged to Amazon CloudWatch Logs and you can use CloudWatch Insight to analyze, monitor, and archive your Amazon DocumentDB profiling data. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on DocumentDB audit logging refer to the Auditing Amazon DocumentDB Events section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbInstance", - "Id": docdbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"instanceId": docdbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class DocdbClusterMultiazCheck(Auditor): - def execute(self): - # find document db clusters - response = documentdb.describe_db_clusters(MaxRecords=100) - myDocDbClusters = response["DBClusters"] - for docdbcluster in myDocDbClusters: - docdbclusterId = str(docdbcluster["DBClusterIdentifier"]) - docdbClusterArn = str(docdbcluster["DBClusterArn"]) - multiAzCheck = str(docdbcluster["MultiAZ"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if multiAzCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbClusterArn + "/docdb-cluster-multi-az-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbclusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[DocDb.4] DocumentDB clusters should be configured for Multi-AZ", - "Description": "DocumentDB cluster " - + docdbclusterId - + " is not configured for Multi-AZ. Amazon DocumentDB helps ensure that there are instances available in your cluster in the unlikely event of an Availability Zone failure. The cluster volume for your Amazon DocumentDB cluster always spans three Availability Zones to provide durable storage with less possibility of data loss. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should be in Multi-AZ configuration refer to the Understanding Amazon DocumentDB Cluster Fault Tolerance section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-fault-tolerance.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbCluster", - "Id": docdbClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"clusterId": docdbclusterId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA-14", - "AICPA TSC A1.2", - "AICPA TSC CC3.1", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbClusterArn + "/docdb-cluster-multi-az-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.4] DocumentDB clusters should be configured for Multi-AZ", - "Description": "DocumentDB cluster " - + docdbclusterId - + " is configured for Multi-AZ.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should be in Multi-AZ configuration refer to the Understanding Amazon DocumentDB Cluster Fault Tolerance section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-fault-tolerance.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbCluster", - "Id": docdbClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"clusterId": docdbclusterId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA-14", - "AICPA TSC A1.2", - "AICPA TSC CC3.1", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class DocdbClusterDeletionProtectionCheck(Auditor): - def execute(self): - # find document db instances - response = documentdb.describe_db_clusters(MaxRecords=100) - myDocDbClusters = response["DBClusters"] - for docdbcluster in myDocDbClusters: - docdbclusterId = str(docdbcluster["DBClusterIdentifier"]) - docdbClusterArn = str(docdbcluster["DBClusterArn"]) - multiAzCheck = str(docdbcluster["MultiAZ"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if multiAzCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbClusterArn + "/docdb-cluster-deletion-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[DocDb.5] DocumentDB clusters should have deletion protection enabled", - "Description": "DocumentDB cluster " - + docdbclusterId - + " does not have deletion protection enabled. To protect your cluster from accidental deletion, you can enable deletion protection. Deletion protection is enabled by default when you create a cluster using the console. However, deletion protection is disabled by default if you create a cluster using the AWS CLI. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have deletion protection enabled refer to the Deletion Protection section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-delete.html#db-cluster-deletion-protection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbCluster", - "Id": docdbClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"clusterId": docdbclusterId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA-14", - "AICPA TSC A1.2", - "AICPA TSC CC3.1", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": docdbClusterArn + "/docdb-cluster-deletion-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": docdbClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.5] DocumentDB clusters should have deletion protection enabled", - "Description": "DocumentDB cluster " - + docdbclusterId - + " has deletion protection enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have deletion protection enabled refer to the Deletion Protection section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-delete.html#db-cluster-deletion-protection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDocumentDbCluster", - "Id": docdbClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"clusterId": docdbclusterId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA-14", - "AICPA TSC A1.2", - "AICPA TSC CC3.1", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class DocumentdbParameterGroupAuditLogCheck(Auditor): - def execute(self): - response = documentdb.describe_db_cluster_parameter_groups() - dbClusterParameters = response["DBClusterParameterGroups"] - for parametergroup in dbClusterParameters: - if str(parametergroup["DBParameterGroupFamily"]) == "docdb3.6": - parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) - parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) - response = documentdb.describe_db_cluster_parameters( - DBClusterParameterGroupName=parameterGroupName - ) - for parameters in response["Parameters"]: - if str(parameters["ParameterName"]) == "audit_logs": - auditLogCheck = str(parameters["ParameterValue"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if auditLogCheck == "disabled": - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/docdb-cluster-parameter-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[DocDb.6] DocumentDB cluster parameter groups should enforce audit logging for DocumentDB databases", - "Description": "DocumentDB cluster parameter group " - + parameterGroupName - + " does not enforce audit logging. Examples of logged events include successful and failed authentication attempts, dropping a collection in a database, or creating an index. By default, auditing is disabled on Amazon DocumentDB and requires that you opt in to use this feature. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have audit logging enabled refer to the Enabling Auditing section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/docdb-cluster-parameter-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.6] DocumentDB cluster parameter groups should enforce audit logging for DocumentDB databases", - "Description": "DocumentDB cluster parameter group " - + parameterGroupName - + " enforces audit logging.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have audit logging enabled refer to the Enabling Auditing section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - else: - pass - - -class DocumentdbParameterGroupTlsEnforcementCheck(Auditor): - def execute(self): - response = documentdb.describe_db_cluster_parameter_groups() - dbClusterParameters = response["DBClusterParameterGroups"] - for parametergroup in dbClusterParameters: - if str(parametergroup["DBParameterGroupFamily"]) == "docdb3.6": - parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) - parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) - response = documentdb.describe_db_cluster_parameters( - DBClusterParameterGroupName=parameterGroupName - ) - for parameters in response["Parameters"]: - if str(parameters["ParameterName"]) == "tls": - tlsEnforcementCheck = str(parameters["ParameterValue"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if tlsEnforcementCheck == "disabled": - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/docdb-cluster-parameter-tls-connections-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[DocDb.7] DocumentDB cluster parameter groups should enforce TLS connections to DocumentDB databases", - "Description": "DocumentDB cluster parameter group " - + parameterGroupName - + " does not enforce TLS connections. When encryption in transit is enabled, secure connections using TLS are required to connect to the cluster. Encryption in transit for an Amazon DocumentDB cluster is managed via the TLS parameter in a cluster parameter group. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have encryption in transit enforced refer to the Managing Amazon DocumentDB Cluster TLS Settings section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/security.encryption.ssl.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "parameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/docdb-cluster-parameter-tls-connections-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.7] DocumentDB cluster parameter groups should enforce TLS connections to DocumentDB databases", - "Description": "DocumentDB cluster parameter group " - + parameterGroupName - + " enforces TLS connections.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster should have encryption in transit enforced refer to the Managing Amazon DocumentDB Cluster TLS Settings section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/security.encryption.ssl.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "parameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - else: - pass - - -class DocumentdbClusterSnapshotEncryptionCheck(Auditor): - def execute(self): - response = documentdb.describe_db_clusters( - Filters=[{"Name": "engine", "Values": ["docdb"]}] - ) - for clusters in response["DBClusters"]: - clusterId = str(clusters["DBClusterIdentifier"]) - response = documentdb.describe_db_cluster_snapshots( - DBClusterIdentifier=clusterId - ) - for snapshots in response["DBClusterSnapshots"]: - clusterSnapshotId = str(snapshots["DBClusterSnapshotIdentifier"]) - clusterSnapshotArn = str(snapshots["DBClusterSnapshotArn"]) - encryptionCheck = str(snapshots["StorageEncrypted"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if encryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterSnapshotArn - + "/docdb-cluster-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterSnapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[DocDb.8] DocumentDB cluster snapshots should be encrypted", - "Description": "DocumentDB cluster snapshot " - + clusterSnapshotId - + " is not encrypted. You encrypt data at rest in your Amazon DocumentDB cluster by specifying the storage encryption option when you create your cluster. Storage encryption is enabled cluster-wide and is applied to all instances, including the primary instance and any replicas. It is also applied to your cluster’s storage volume, data, indexes, logs, automated backups, and snapshots. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster snapshot should be encrypted refer to the Limitations for Amazon DocumentDB Encrypted Clusters section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html#encryption-at-rest-limits", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": clusterSnapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": clusterSnapshotId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterSnapshotArn - + "/docdb-cluster-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterSnapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.8] DocumentDB cluster snapshots should be encrypted", - "Description": "DocumentDB cluster snapshot " - + clusterSnapshotId - + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster snapshot should be encrypted refer to the Limitations for Amazon DocumentDB Encrypted Clusters section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html#encryption-at-rest-limits", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": clusterSnapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": clusterSnapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class DocumentdbClusterSnapshotPublicShareCheck(Auditor): - def execute(self): - response = documentdb.describe_db_clusters( - Filters=[{"Name": "engine", "Values": ["docdb"]}] - ) - for clusters in response["DBClusters"]: - clusterId = str(clusters["DBClusterIdentifier"]) - response = documentdb.describe_db_cluster_snapshots( - DBClusterIdentifier=clusterId - ) - for snapshots in response["DBClusterSnapshots"]: - clusterSnapshotId = str(snapshots["DBClusterSnapshotIdentifier"]) - clusterSnapshotArn = str(snapshots["DBClusterSnapshotArn"]) - response = documentdb.describe_db_cluster_snapshot_attributes( - DBClusterSnapshotIdentifier=clusterSnapshotId - ) - for snapshotattributes in response["DBClusterSnapshotAttributesResult"][ - "DBClusterSnapshotAttributes" - ]: - if str(snapshotattributes["AttributeName"]) == "restore": - valueCheck = str(snapshotattributes["AttributeValues"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if valueCheck == "['all']": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterSnapshotArn - + "/docdb-cluster-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterSnapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[DocDb.9] DocumentDB cluster snapshots should not be publicly shared", - "Description": "DocumentDB cluster snapshot " - + clusterSnapshotId - + " is publicly shared. You can share a manual snapshot with up to 20 other AWS accounts. You can also share an unencrypted manual snapshot as public, which makes the snapshot available to all accounts. Take care when sharing a snapshot as public so that none of your private information is included in any of your public snapshots. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster snapshot should not be publicly shared refer to the Sharing Amazon DocumentDB Cluster Snapshots section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshot-share.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": clusterSnapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"snapshotId": clusterSnapshotId} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterSnapshotArn - + "/docdb-cluster-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterSnapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[DocDb.9] DocumentDB cluster snapshots should not be publicly shared", - "Description": "DocumentDB cluster snapshot " - + clusterSnapshotId - + " is not publicly shared, however, it may be shared with other accounts. You should periodically review who has snapshots shared with them to ensure they are still authorized", - "Remediation": { - "Recommendation": { - "Text": "If your DocumentDB cluster snapshot should not be publicly shared refer to the Sharing Amazon DocumentDB Cluster Snapshots section in the Amazon DocumentDB Developer Guide", - "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshot-share.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": clusterSnapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"snapshotId": clusterSnapshotId} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass diff --git a/auditors/Amazon_EBS_Auditor.py b/auditors/Amazon_EBS_Auditor.py deleted file mode 100644 index d52356b7..00000000 --- a/auditors/Amazon_EBS_Auditor.py +++ /dev/null @@ -1,885 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -ec2 = boto3.client("ec2") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through EBS volumes -response = ec2.describe_volumes(DryRun=False, MaxResults=500) -myEbsVolumes = response["Volumes"] -# loop through EBS snapshots -response = ec2.describe_snapshots(OwnerIds=[awsAccountId], DryRun=False) -myEbsSnapshots = response["Snapshots"] - - -class EbsVolumeAttachmentCheck(Auditor): - def execute(self): - for volumes in myEbsVolumes: - ebsVolumeId = str(volumes["VolumeId"]) - ebsVolumeArn = ( - "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId - ) - ebsAttachments = volumes["Attachments"] - for attachments in ebsAttachments: - ebsAttachmentState = str(attachments["State"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ebsAttachmentState != "attached": - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-attachment-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EBS.1] EBS Volumes should be in an attached state", - "Description": "EBS Volume " - + ebsVolumeId - + " is not in an attached state. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be attached refer to the Attaching an Amazon EBS Volume to an Instance section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-attachment-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.1] EBS Volumes should be in an attached state", - "Description": "EBS Volume " - + ebsVolumeId - + " is in an attached state.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be attached refer to the Attaching an Amazon EBS Volume to an Instance section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EbsVolumeDeleteOnTerminationCheck(Auditor): - def execute(self): - for volumes in myEbsVolumes: - ebsVolumeId = str(volumes["VolumeId"]) - ebsVolumeArn = ( - "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId - ) - ebsAttachments = volumes["Attachments"] - for attachments in ebsAttachments: - ebsDeleteOnTerminationCheck = str(attachments["DeleteOnTermination"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ebsDeleteOnTerminationCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-delete-on-termination-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EBS.2] EBS Volumes should be configured to be deleted on termination", - "Description": "EBS Volume " - + ebsVolumeId - + " is not configured to be deleted on termination. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be deleted on instance termination refer to the Preserving Amazon EBS Volumes on Instance Termination section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#preserving-volumes-on-termination", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-delete-on-termination-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.2] EBS Volumes should be configured to be deleted on termination", - "Description": "EBS Volume " - + ebsVolumeId - + " is configured to be deleted on termination.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be deleted on instance termination refer to the Preserving Amazon EBS Volumes on Instance Termination section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#preserving-volumes-on-termination", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EbsVolumeEncryptionCheck(Auditor): - def execute(self): - for volumes in myEbsVolumes: - ebsVolumeId = str(volumes["VolumeId"]) - ebsVolumeArn = ( - "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId - ) - ebsEncryptionCheck = str(volumes["Encrypted"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ebsEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EBS.3] EBS Volumes should be encrypted", - "Description": "EBS Volume " - + ebsVolumeId - + " is not encrypted. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be encrypted refer to the Amazon EBS Encryption section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ebsVolumeArn + "/ebs-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ebsVolumeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.3] EBS Volumes should be encrypted", - "Description": "EBS Volume " + ebsVolumeId + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS volume should be encrypted refer to the Amazon EBS Encryption section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Volume", - "Id": ebsVolumeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"volumeId": ebsVolumeId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EbsSnapshotEncryptionCheck(Auditor): - def execute(self): - for snapshots in myEbsSnapshots: - snapshotId = str(snapshots["SnapshotId"]) - snapshotArn = "arn:aws:ec2:" + awsRegion + "::snapshot/" + snapshotId - snapshotEncryptionCheck = str(snapshots["Encrypted"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if snapshotEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/ebs-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EBS.4] EBS Snapshots should be encrypted", - "Description": "EBS Snapshot " - + snapshotId - + " is not encrypted. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your EBS snapshot should be encrypted refer to the Encryption Support for Snapshots section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/EBSSnapshots.html#encryption-support", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Snapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/ebs-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.4] EBS Snapshots should be encrypted", - "Description": "EBS Snapshot " + snapshotId + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS snapshot should be encrypted refer to the Encryption Support for Snapshots section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/EBSSnapshots.html#encryption-support", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Snapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EbsSnapshotPublicCheck(Auditor): - def execute(self): - for snapshots in myEbsSnapshots: - snapshotId = str(snapshots["SnapshotId"]) - snapshotArn = "arn:aws:ec2:" + awsRegion + "::snapshot/" + snapshotId - response = ec2.describe_snapshot_attribute( - Attribute="createVolumePermission", SnapshotId=snapshotId, DryRun=False - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if str(response["CreateVolumePermissions"]) == "[]": - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/ebs-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.5] EBS Snapshots should not be public", - "Description": "EBS Snapshot " + snapshotId + " is private.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Snapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - for permissions in response["CreateVolumePermissions"]: - # {'Group': 'all'} denotes public - # you should still audit accounts you have shared - if str(permissions) == "{'Group': 'all'}": - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/ebs-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[EBS.5] EBS Snapshots should not be public", - "Description": "EBS Snapshot " - + snapshotId - + " is public. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Snapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"snapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/ebs-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.5] EBS Snapshots should not be public", - "Description": "EBS Snapshot " - + snapshotId - + " is private, however, this snapshot has been identified as being shared with other accounts. You should audit these accounts to ensure they are still authorized to have this snapshot shared with them.", - "Remediation": { - "Recommendation": { - "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Snapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"SnapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class EbsAccountEncryptionByDefaultCheck(Auditor): - def execute(self): - response = ec2.get_ebs_encryption_by_default(DryRun=False) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - ) - if str(response["EbsEncryptionByDefault"]) == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + awsRegion + "/ebs-account-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId + "/" + awsRegion, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EBS.6] Account-level EBS Volume encryption should be enabled", - "Description": "Account-level EBS volume encryption is not enabled for AWS Account " - + awsAccountId - + " in " - + awsRegion - + ". Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on Account-level encryption refer to the Encryption by Default to an Instance section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html#encryption-by-default", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + awsRegion + "/ebs-account-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId + "/" + awsRegion, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EBS.6] Account-level EBS Volume encryption should be enabled", - "Description": "Account-level EBS volume encryption is enabled for AWS Account " - + awsAccountId - + " in " - + awsRegion - + ".", - "Remediation": { - "Recommendation": { - "Text": "For information on Account-level encryption refer to the Encryption by Default to an Instance section of the Amazon Elastic Compute Cloud User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html#encryption-by-default", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_EC2_Auditor.py b/auditors/Amazon_EC2_Auditor.py deleted file mode 100644 index cb373afe..00000000 --- a/auditors/Amazon_EC2_Auditor.py +++ /dev/null @@ -1,199 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -sts = boto3.client("sts") -ec2 = boto3.client("ec2") -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] - - -class Ec2Imdsv2Check(Auditor): - def execute(self): - try: - response = ec2.describe_instances(MaxResults=1000) - for r in response["Reservations"]: - for i in r["Instances"]: - instanceId = str(i["InstanceId"]) - instanceArn = ( - "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + ":instance/" + instanceId - ) - instanceType = str(i["InstanceType"]) - instanceImage = str(i["ImageId"]) - subnetId = str(i["SubnetId"]) - vpcId = str(i["VpcId"]) - instanceLaunchedAt = str(i["LaunchTime"]) - metadataServiceCheck = str(i["MetadataOptions"]["HttpEndpoint"]) - if metadataServiceCheck == "enabled": - imdsv2Check = str(i["MetadataOptions"]["HttpTokens"]) - if imdsv2Check != "required": - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-imdsv2-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EC2.1] EC2 Instances should be configured to use instance metadata service V2 (IMDSv2)", - "Description": "EC2 Instance " - + instanceId - + " is not configured to use instance metadata service V2 (IMDSv2). IMDSv2 adds new “belt and suspenders” protections for four types of vulnerabilities that could be used to try to access the IMDS. These new protections go well beyond other types of mitigations, while working seamlessly with existing mitigations such as restricting IAM roles and using local firewall rules to restrict access to the IMDS. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "To learn how to configure IMDSv2 refer to the Transitioning to Using Instance Metadata Service Version 2 section of the Amazon EC2 User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-transition-to-version-2", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": vpcId, - "SubnetId": subnetId, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-4", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-5", - "NIST SP 800-53 AC-6", - "NIST SP 800-53 AC-14", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-24", - "AICPA TSC CC6.3", - "ISO 27001:2013 A.6.1.2", - "ISO 27001:2013 A.9.1.2", - "ISO 27001:2013 A.9.2.3", - "ISO 27001:2013 A.9.4.1", - "ISO 27001:2013 A.9.4.4", - "ISO 27001:2013 A.9.4.5", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) - else: - try: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # create Sec Hub finding - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-imdsv2-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EC2.1] EC2 Instances should be configured to use instance metadata service V2 (IMDSv2)", - "Description": "EC2 Instance " - + instanceId - + " is using instance metadata service V2 (IMDSv2). IMDSv2 adds new “belt and suspenders” protections for four types of vulnerabilities that could be used to try to access the IMDS. These new protections go well beyond other types of mitigations, while working seamlessly with existing mitigations such as restricting IAM roles and using local firewall rules to restrict access to the IMDS. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "To learn how to configure IMDSv2 refer to the Transitioning to Using Instance Metadata Service Version 2 section of the Amazon EC2 User Guide", - "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-transition-to-version-2", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": vpcId, - "SubnetId": subnetId, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": ["NIST CSF PR.PT-3"], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - else: - pass - except Exception as e: - print(e) diff --git a/auditors/Amazon_EC2_SSM_Auditor.py b/auditors/Amazon_EC2_SSM_Auditor.py deleted file mode 100644 index fc8d0e04..00000000 --- a/auditors/Amazon_EC2_SSM_Auditor.py +++ /dev/null @@ -1,759 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# create boto3 clients -sts = boto3.client("sts") -ec2 = boto3.client("ec2") -ssm = boto3.client("ssm") -securityhub = boto3.client("securityhub") -# create env vars -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through ec2 instances -response = ec2.describe_instances(DryRun=False, MaxResults=1000) -myEc2InstanceReservations = response["Reservations"] - - -class Ec2InstanceSsmManagedCheck(Auditor): - def execute(self): - for reservations in myEc2InstanceReservations: - for instances in reservations["Instances"]: - instanceId = str(instances["InstanceId"]) - instanceArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":instance/" - + instanceId - ) - instanceType = str(instances["InstanceType"]) - instanceImage = str(instances["ImageId"]) - instanceVpc = str(instances["VpcId"]) - instanceSubnet = str(instances["SubnetId"]) - instanceLaunchedAt = str(instances["LaunchTime"]) - try: - response = ssm.describe_instance_information( - InstanceInformationFilterList=[ - {"key": "InstanceIds", "valueSet": [instanceId]}, - ] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if str(response["InstanceInformationList"]) == "[]": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-managed-by-ssm-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EC2-SSM.1] EC2 Instances should be managed by Systems Manager", - "Description": "EC2 Instance " - + instanceId - + " is not managed by Systems Manager. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "To learn how to configure Systems Manager and associated instances refer to the Setting Up AWS Systems Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/en_us/systems-manager/latest/userguide/systems-manager-setting-up.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-managed-by-ssm-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EC2-SSM.1] EC2 Instances should be managed by Systems Manager", - "Description": "EC2 Instance " - + instanceId - + " is managed by Systems Manager.", - "Remediation": { - "Recommendation": { - "Text": "To learn how to configure Systems Manager and associated instances refer to the Setting Up AWS Systems Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/en_us/systems-manager/latest/userguide/systems-manager-setting-up.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class SsmInstaceAgentUpdateCheck(Auditor): - def execute(self): - for reservations in myEc2InstanceReservations: - for instances in reservations["Instances"]: - instanceId = str(instances["InstanceId"]) - instanceArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":instance/" - + instanceId - ) - instanceType = str(instances["InstanceType"]) - instanceImage = str(instances["ImageId"]) - instanceVpc = str(instances["VpcId"]) - instanceSubnet = str(instances["SubnetId"]) - instanceLaunchedAt = str(instances["LaunchTime"]) - response = ssm.describe_instance_information() - myManagedInstances = response["InstanceInformationList"] - for instances in myManagedInstances: - latestVersionCheck = str(instances["IsLatestVersion"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if latestVersionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-ssm-agent-latest-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EC2-SSM.2] EC2 Instances managed by Systems Manager should have the latest SSM Agent installed", - "Description": "EC2 Instance " - + instanceId - + " does not have the latest SSM Agent installed. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on automating updates to the SSM Agent refer to the Automate Updates to SSM Agent section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-automatic-updates.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-ssm-agent-latest-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EC2-SSM.2] EC2 Instances managed by Systems Manager should have the latest SSM Agent installed", - "Description": "EC2 Instance " - + instanceId - + " has the latest SSM Agent installed.", - "Remediation": { - "Recommendation": { - "Text": "For information on automating updates to the SSM Agent refer to the Automate Updates to SSM Agent section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-automatic-updates.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class SsmInstanceAssociationCheck(Auditor): - def execute(self): - for reservations in myEc2InstanceReservations: - for instances in reservations["Instances"]: - instanceId = str(instances["InstanceId"]) - instanceArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":instance/" - + instanceId - ) - instanceType = str(instances["InstanceType"]) - instanceImage = str(instances["ImageId"]) - instanceVpc = str(instances["VpcId"]) - instanceSubnet = str(instances["SubnetId"]) - instanceLaunchedAt = str(instances["LaunchTime"]) - response = ssm.describe_instance_information() - myManagedInstances = response["InstanceInformationList"] - for instances in myManagedInstances: - associationStatusCheck = str(instances["AssociationStatus"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if associationStatusCheck != "Success": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-ssm-association-success-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EC2-SSM.3] EC2 Instances managed by Systems Manager should have a successful Association status", - "Description": "EC2 Instance " - + instanceId - + " does not have a successful Association status. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on Systems Manager Associations refer to the Working with Associations in Systems Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-associations.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-ssm-association-success-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EC2-SSM.3] EC2 Instances managed by Systems Manager should have a successful Association status", - "Description": "EC2 Instance " - + instanceId - + " has a successful Association status.", - "Remediation": { - "Recommendation": { - "Text": "For information on Systems Manager Associations refer to the Working with Associations in Systems Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-associations.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class SsmInstancePatchStateState(Auditor): - def execute(self): - for reservations in myEc2InstanceReservations: - for instances in reservations["Instances"]: - instanceId = str(instances["InstanceId"]) - instanceArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":instance/" - + instanceId - ) - instanceType = str(instances["InstanceType"]) - instanceImage = str(instances["ImageId"]) - instanceVpc = str(instances["VpcId"]) - instanceSubnet = str(instances["SubnetId"]) - instanceLaunchedAt = str(instances["LaunchTime"]) - response = ssm.describe_instance_information() - try: - response = ssm.describe_instance_patch_states( - InstanceIds=[instanceId] - ) - patchStatesCheck = str(response["InstancePatchStates"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if patchStatesCheck == "[]": - print("no patch info") - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-patch-manager-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", - "Description": "EC2 Instance " - + instanceId - + " does not have any patch information recorded and is likely not managed by Patch Manager. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - patchStates = response["InstancePatchStates"] - for patches in patchStates: - failedPatchCheck = str(patches["FailedCount"]) - missingPatchCheck = str(patches["MissingCount"]) - if failedPatchCheck != "0" or missingPatchCheck != "0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-patch-manager-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", - "Description": "EC2 Instance " - + instanceId - + " is missing patches or has patches that failed to apply. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/ec2-patch-manager-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", - "Description": "EC2 Instance " - + instanceId - + " has the latest patches installed by Patch Manager.", - "Remediation": { - "Recommendation": { - "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", - "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": instanceType, - "ImageId": instanceImage, - "VpcId": instanceVpc, - "SubnetId": instanceSubnet, - "LaunchedAt": instanceLaunchedAt, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_EC2_Security_Group_Auditor.py b/auditors/Amazon_EC2_Security_Group_Auditor.py deleted file mode 100644 index 0c93625c..00000000 --- a/auditors/Amazon_EC2_Security_Group_Auditor.py +++ /dev/null @@ -1,4068 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -ec2 = boto3.client("ec2") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through security groups -response = ec2.describe_security_groups() -mySgs = response["SecurityGroups"] - - -class SecurityGroupAllOpenCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ipProtocol == "-1" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-all-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.1] Security groups should not allow unrestricted access to all ports and protocols", - "Description": "Security group " - + sgName - + " allows unrestricted access to all ports and protocols. Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif ipProtocol == "-1" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-all-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.1] Security groups should not allow unrestricted access to all ports and protocols", - "Description": "Security group " - + sgName - + " does not allow unrestricted access to all ports and protocols. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenFtpCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - toPort == "20" - and fromPort == "21" - and cidrIpRange == "0.0.0.0/0" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-ftp-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.2] Security groups should not allow unrestricted File Transfer Protocol (FTP) access", - "Description": "Security group " - + sgName - + " allows unrestricted File Transfer Protocol (FTP) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif ( - toPort == "20" - and fromPort == "21" - and cidrIpRange != "0.0.0.0/0" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-ftp-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.2] Security groups should not allow unrestricted File Transfer Protocol (FTP) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted File Transfer Protocol (FTP) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenTelnetCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "23" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-telnet-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.3] Security groups should not allow unrestricted TelNet access", - "Description": "Security group " - + sgName - + " allows unrestricted TelNet access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "23" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-telnet-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.3] Security groups should not allow unrestricted TelNet access", - "Description": "Security group " - + sgName - + " does not allow unrestricted TelNet access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenDcomRpcCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "135" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-telnet-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.4] Security groups should not allow unrestricted Windows RPC DCOM access", - "Description": "Security group " - + sgName - + " allows unrestricted Windows RPC DCOM access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Attack signature information, refer to Threatl Intel Source URL", - "Source": "Symantec Security Center", - "SourceUrl": "https://www.symantec.com/security_response/attacksignatures/detail.jsp?asid=20387", - } - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - if toPort and fromPort == "135" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-wsrpc-dcom-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.4] Security groups should not allow unrestricted Windows RPC DCOM access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Windows RPC DCOM access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Attack signature information, refer to Threatl Intel Source URL", - "Source": "Symantec Security Center", - "SourceUrl": "https://www.symantec.com/security_response/attacksignatures/detail.jsp?asid=20387", - } - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenSmbCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "445" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-smb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.5] Security groups should not allow unrestricted Server Message Blocks (SMB) access", - "Description": "Security group " - + sgName - + " allows unrestricted Server Message Blocks (SMB) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/modules/exploit/windows/smb/ms17_010_eternalblue", - }, - { - "Category": "BACKDOOR", - "Value": "How to use EternalBlue to Exploit SMB Port using Public Wi-Fi", - "Source": "Medium", - "SourceUrl": "https://medium.com/@melvinshb/how-to-use-eternalblue-to-exploit-smb-port-using-public-wi-fi-79a996821767", - }, - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "445" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-smb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.5] Security groups should not allow unrestricted Server Message Blocks (SMB) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Server Message Blocks (SMB) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/modules/exploit/windows/smb/ms17_010_eternalblue", - }, - { - "Category": "BACKDOOR", - "Value": "How to use EternalBlue to Exploit SMB Port using Public Wi-Fi", - "Source": "Medium", - "SourceUrl": "https://medium.com/@melvinshb/how-to-use-eternalblue-to-exploit-smb-port-using-public-wi-fi-79a996821767", - }, - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenMssqlCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "1433" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-mssql-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.6] Security groups should not allow unrestricted Microsoft SQL Server (MSSQL) access", - "Description": "Security group " - + sgName - + " allows unrestricted Microsoft SQL Server (MSSQL) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0618: Microsoft SQL Server Reporting Services Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0618", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2019-0819: Microsoft SQL Server Analysis Services Information Disclosure Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2019-0819", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2018-8273: Microsoft SQL Server Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2018-8273", - }, - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "1433" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-mssql-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.6] Security groups should not allow unrestricted Microsoft SQL Server (MSSQL) access", - "Description": "Security group " - + sgName - + " allows unrestricted Microsoft SQL Server (MSSQL) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0618: Microsoft SQL Server Reporting Services Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0618", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2019-0819: Microsoft SQL Server Analysis Services Information Disclosure Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2019-0819", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2018-8273: Microsoft SQL Server Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2018-8273", - }, - ], - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenOracleCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "1521" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-oracledb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.7] Security groups should not allow unrestricted Oracle database (TCP 1521) access", - "Description": "Security group " - + sgName - + " allows unrestricted Oracle database (TCP 1521) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "1521" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-oracledb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.7] Security groups should not allow unrestricted Oracle database (TCP 1521) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Oracle database (TCP 1521) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenMysqlMariadbCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "3306" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-mysql-mariadb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.8] Security groups should not allow unrestricted MySQL or MariaDB database (TCP 3306) access", - "Description": "Security group " - + sgName - + " allows unrestricted MySQL or MariaDB database (TCP 3306) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - if toPort and fromPort == "3306" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-mysql-mariadb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.8] Security groups should not allow unrestricted MySQL or MariaDB database (TCP 3306) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted MySQL or MariaDB database (TCP 3306) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenRdpCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "3389" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-rdp-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.9] Security groups should not allow unrestricted Remote Desktop Protocol (RDP) access", - "Description": "Security group " - + sgName - + " allows unrestricted Remote Desktop Protocol (RDP) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0660: Windows Remote Desktop Protocol (RDP) Denial of Service Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0610: Windows Remote Desktop Gateway (RD Gateway) Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0610", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "3389" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-rdp-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.9] Security groups should not allow unrestricted Remote Desktop Protocol (RDP) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Remote Desktop Protocol (RDP) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0660: Windows Remote Desktop Protocol (RDP) Denial of Service Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", - }, - { - "Category": "BACKDOOR", - "Value": "Microsoft CVE-2020-0610: Windows Remote Desktop Gateway (RD Gateway) Remote Code Execution Vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0610", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenPostgresqlCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "5432" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-postgresql-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.10] Security groups should not allow unrestricted PostgreSQL datbase (TCP 5432) access", - "Description": "Security group " - + sgName - + " allows unrestricted PostgreSQL datbase (TCP 5432) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "5432" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-postgresql-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.10] Security groups should not allow unrestricted PostgreSQL datbase (TCP 5432) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted PostgreSQL datbase (TCP 5432) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenKibanaCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "5601" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-kibana-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.11] Security groups should not allow unrestricted access to Kibana (TCP 5601)", - "Description": "Security group " - + sgName - + " allows unrestricted access to Kibana (TCP 5601) on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "CVE-2019-7609: Exploit Script Available for Kibana Remote Code Execution Vulnerability", - "Source": "Tenable Blog", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", - }, - { - "Category": "BACKDOOR", - "Value": "Red Hat OpenShift: CVE-2019-7608: kibana: Cross-site scripting vulnerability permits perform destructive actions on behalf of other Kibana users", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redhat-openshift-cve-2019-7608", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "5601" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-kibana-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.11] Security groups should not allow unrestricted access to Kibana (TCP 5601)", - "Description": "Security group " - + sgName - + " does not allow unrestricted access to Kibana (TCP 5601) on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "CVE-2019-7609: Exploit Script Available for Kibana Remote Code Execution Vulnerability", - "Source": "Tenable Blog", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", - }, - { - "Category": "BACKDOOR", - "Value": "Red Hat OpenShift: CVE-2019-7608: kibana: Cross-site scripting vulnerability permits perform destructive actions on behalf of other Kibana users", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redhat-openshift-cve-2019-7608", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenRedisCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "6379" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-redis-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.12] Security groups should not allow unrestricted Redis (TCP 6379) access", - "Description": "Security group " - + sgName - + " allows unrestricted Redis (TCP 6379) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Redis 4.x / 5.x - Unauthenticated Code Execution (Metasploit)", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/47195", - }, - { - "Category": "BACKDOOR", - "Value": "Redis: Improper Input Validation (CVE-2013-0178)", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redislabs-redis-cve-2013-0178", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "6379" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-redis-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.12] Security groups should not allow unrestricted Redis (TCP 6379) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Redis (TCP 6379) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Redis 4.x / 5.x - Unauthenticated Code Execution (Metasploit)", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/47195", - }, - { - "Category": "BACKDOOR", - "Value": "Redis: Improper Input Validation (CVE-2013-0178)", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redislabs-redis-cve-2013-0178", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenSplunkdCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "8089" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-splunkd-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.13] Security groups should not allow unrestricted Splunkd (TCP 8089) access", - "Description": "Security group " - + sgName - + " allows unrestricted Splunkd (TCP 8089) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Splunk - Remote Command Execution", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/18245", - }, - { - "Category": "BACKDOOR", - "Value": "Splunk Web Interface Login Utility", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/modules/auxiliary/scanner/http/splunk_web_login", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "8089" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-splunkd-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.13] Security groups should not allow unrestricted Splunkd (TCP 8089) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Splunkd (TCP 8089) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "Splunk - Remote Command Execution", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/18245", - }, - { - "Category": "BACKDOOR", - "Value": "Splunk Web Interface Login Utility", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/modules/auxiliary/scanner/http/splunk_web_login", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenElasticsearch1Check(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "9200" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-elasticsearch-9200-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.14] Security groups should not allow unrestricted Elasticsearch (TCP 9200) access", - "Description": "Security group " - + sgName - + " allows unrestricted Elasticsearch (TCP 9200) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "9200" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-elasticsearch-9200-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.14] Security groups should not allow unrestricted Elasticsearch (TCP 9200) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Elasticsearch (TCP 9200) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenElasticsearch2Check(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "9300" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-elasticsearch-9300-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.15] Security groups should not allow unrestricted Elasticsearch (TCP 9300) access", - "Description": "Security group " - + sgName - + " allows unrestricted Elasticsearch (TCP 9300) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "9300" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-elasticsearch-9300-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.15] Security groups should not allow unrestricted Elasticsearch (TCP 9300) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Elasticsearch (TCP 9300) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenMemcachedCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - toPort - and fromPort == "11211" - and ipProtocol == "udp" - and cidrIpRange == "0.0.0.0/0" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-memcached-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.16] Security groups should not allow unrestricted Memcached (UDP 11211) access", - "Description": "Security group " - + sgName - + " allows unrestricted Memcached (UDP 11211) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "memcached 1.4.2 - Memory Consumption Remote Denial of Service", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/33850", - }, - { - "Category": "BACKDOOR", - "Value": "Ubuntu: USN-4125-1 (CVE-2019-15026): Memcached vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/ubuntu-cve-2019-15026", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif ( - toPort - and fromPort == "11211" - and ipProtocol == "udp" - and cidrIpRange != "0.0.0.0/0" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-memcached-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.16] Security groups should not allow unrestricted Memcached (UDP 11211) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Memcached (UDP 11211) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Category": "BACKDOOR", - "Value": "memcached 1.4.2 - Memory Consumption Remote Denial of Service", - "Source": "ExploitDB", - "SourceUrl": "https://www.exploit-db.com/exploits/33850", - }, - { - "Category": "BACKDOOR", - "Value": "Ubuntu: USN-4125-1 (CVE-2019-15026): Memcached vulnerability", - "Source": "Rapid7 Vulnerability & Exploit Database", - "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/ubuntu-cve-2019-15026", - }, - ], - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenRedshiftCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "5439" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-redshift-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.17] Security groups should not allow unrestricted Redshift (TCP 5439) access", - "Description": "Security group " - + sgName - + " allows unrestricted Redshift (TCP 5439) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "5439" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-redshift-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.17] Security groups should not allow unrestricted Redshift (TCP 5439) access", - "Description": "Security group " - + sgName - + " does not allow unrestricted Redshift (TCP 5439) access on " - + ipProtocol - + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenDocumentdbCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "27017" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-documentdb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.18] Security groups should not allow unrestricted DocumentDB (TCP 27017) access", - "Description": "Security group " - + sgName - + " allows unrestricted DocumentDB (TCP 27017) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "27017" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-documentdb-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.18] Security groups should not allow unrestricted DocumentDB (TCP 27017) access", - "Description": "Security group " - + sgName - + " allows unrestricted DocumentDB (TCP 27017) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenCassandraCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "9142" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-cassandra-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.19] Security groups should not allow unrestricted Cassandra (TCP 9142) access", - "Description": "Security group " - + sgName - + " allows unrestricted Cassandra (TCP 9142) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "9142" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-cassandra-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.19] Security groups should not allow unrestricted Cassandra (TCP 9142) access", - "Description": "Security group " - + sgName - + " allows unrestricted Cassandra (TCP 9142) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class SecurityGroupOpenKafkaCheck(Auditor): - def execute(self): - for secgroup in mySgs: - sgName = str(secgroup["GroupName"]) - sgId = str(secgroup["GroupId"]) - sgArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":security-group/" - + sgId - ) - for permissions in secgroup["IpPermissions"]: - try: - fromPort = str(permissions["FromPort"]) - except Exception as e: - if str(e) == "'FromPort'": - pass - else: - print(e) - try: - toPort = str(permissions["ToPort"]) - except Exception as e: - if str(e) == "'ToPort'": - pass - else: - print(e) - try: - ipProtocol = str(permissions["IpProtocol"]) - except Exception as e: - print(e) - ipRanges = permissions["IpRanges"] - for cidrs in ipRanges: - cidrIpRange = str(cidrs["CidrIp"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if toPort and fromPort == "9092" and cidrIpRange == "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-kafka-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[SecurityGroup.20] Security groups should not allow unrestricted Kafka streams (TCP 9092) access", - "Description": "Security group " - + sgName - + " allows unrestricted Kafka streams (TCP 9092) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif toPort and fromPort == "9092" and cidrIpRange != "0.0.0.0/0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": sgArn - + "/" - + ipProtocol - + "/security-group-kafka-open-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": sgArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SecurityGroup.20] Security groups should not allow unrestricted Kafka streams (TCP 9092) access", - "Description": "Security group " - + sgName - + " allows unrestricted Kafka streams (TCP 9092) access on " - + ipProtocol - + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", - "Remediation": { - "Recommendation": { - "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", - "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2SecurityGroup", - "Id": sgArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2SecurityGroup": { - "GroupName": sgName, - "GroupId": sgId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass diff --git a/auditors/Amazon_ECR_Auditor.py b/auditors/Amazon_ECR_Auditor.py deleted file mode 100644 index 48e61faa..00000000 --- a/auditors/Amazon_ECR_Auditor.py +++ /dev/null @@ -1,610 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -ecr = boto3.client("ecr") -sts = boto3.client("sts") -# create account id & region variables -awsAccount = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through ECR repos -response = ecr.describe_repositories(maxResults=1000) -myRepos = response["repositories"] - - -class EcrRepoVulnScanCheck(Auditor): - def execute(self): - for repo in myRepos: - repoArn = str(repo["repositoryArn"]) - repoName = str(repo["repositoryName"]) - scanningConfig = str(repo["imageScanningConfiguration"]["scanOnPush"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if scanningConfig == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-no-scan", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ECR.1] ECR repositories should be configured to scan images on push", - "Description": "ECR repository " - + repoName - + " is not configured to scan images on push. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to scan on push refer to the Image Scanning section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.CM-8", - "NIST SP 800-53 RA-5", - "AICPA TSC CC7.1", - "ISO 27001:2013 A.12.6.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-no-scan", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECR.1] ECR repositories should be configured to scan images on push", - "Description": "ECR repository " - + repoName - + " is configured to scan images on push.", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to scan on push refer to the Image Scanning section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.CM-8", - "NIST SP 800-53 RA-5", - "AICPA TSC CC7.1", - "ISO 27001:2013 A.12.6.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EcrRepoImageLifecyclePolicyCheck(Auditor): - def execute(self): - for repo in myRepos: - repoArn = str(repo["repositoryArn"]) - repoName = str(repo["repositoryName"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing finding - response = ecr.get_lifecycle_policy(repositoryName=repoName) - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-lifecycle-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECR.2] ECR repositories should be have an image lifecycle policy configured", - "Description": "ECR repository " - + repoName - + " does not have an image lifecycle policy configured. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to have an image lifecycle policy refer to the Amazon ECR Lifecycle Policies section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-lifecycle-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ECR.2] ECR repositories should be have an image lifecycle policy configured", - "Description": "ECR repository " - + repoName - + " does not have an image lifecycle policy configured. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to have an image lifecycle policy refer to the Amazon ECR Lifecycle Policies section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class EcrRepoPermissionPolicy(Auditor): - def execute(self): - for repo in myRepos: - repoArn = str(repo["repositoryArn"]) - repoName = str(repo["repositoryName"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing finding - response = ecr.get_repository_policy(repositoryName=repoName) - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-repo-access-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECR.3] ECR repositories should be have a repository policy configured", - "Description": "ECR repository " - + repoName - + " has a repository policy configured.", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to have a repository policy refer to the Amazon ECR Repository Policies section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoArn + "/ecr-repo-access-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": repoArn, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ECR.3] ECR repositories should be have a repository policy configured", - "Description": "ECR repository " - + repoName - + " does not have a repository policy configured. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your repository should be configured to have a repository policy refer to the Amazon ECR Repository Policies section in the Amazon ECR User Guide", - "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcrRepository", - "Id": repoArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"RepositoryName": repoName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class EcrLatestImageVulnCheck(Auditor): - def execute(self): - for repo in myRepos: - repoArn = str(repo["repositoryArn"]) - repoName = str(repo["repositoryName"]) - scanningConfig = str(repo["imageScanningConfiguration"]["scanOnPush"]) - if scanningConfig == "True": - try: - response = ecr.describe_images( - repositoryName=repoName, - filter={"tagStatus": "TAGGED"}, - maxResults=1000, - ) - for images in response["imageDetails"]: - imageDigest = str(images["imageDigest"]) - # use the first tag only as we need it to create the canonical ID for the Resource.Id in the ASFF for the Container Resource.Type - imageTag = str(images["imageTags"][0]) - imageVulnCheck = str( - images["imageScanFindingsSummary"]["findingSeverityCounts"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if imageVulnCheck != "{}": - vulnDeepLink = ( - "https://console.aws.amazon.com/ecr/repositories/" - + repoName - + "/image/" - + imageDigest - + "/scan-results?region=" - + awsRegion - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoName - + "/" - + imageDigest - + "/ecr-latest-image-vuln-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": imageDigest, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/Vulnerabilities/CVE", - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ECR.4] The latest image in an ECR Repository should not have any vulnerabilities", - "Description": "The latest image in the ECR repository " - + repoName - + " has the following vulnerabilities reported: " - + imageVulnCheck - + ". Refer to the SourceUrl or Remediation.Recommendation.Url to review the specific vulnerabilities and remediation information from ECR.", - "Remediation": { - "Recommendation": { - "Text": "Click here to navigate to the ECR Vulnerability console for this image", - "Url": vulnDeepLink, - } - }, - "SourceUrl": vulnDeepLink, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Container", - "Id": repoName + ":" + imageTag, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Container": { - "Name": repoName + ":" + imageTag, - "ImageId": imageDigest, - }, - "Other": { - "RepositoryName": repoName, - "RepositoryArn": repoArn, - }, - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.CM-8", - "NIST SP 800-53 RA-5", - "AICPA TSC CC7.1", - "ISO 27001:2013 A.12.6.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": repoName - + "/" - + imageDigest - + "/ecr-latest-image-vuln-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccount - + ":product/" - + awsAccount - + "/default", - "GeneratorId": imageDigest, - "AwsAccountId": awsAccount, - "Types": [ - "Software and Configuration Checks/Vulnerabilities/CVE", - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECR.4] The latest image in an ECR Repository should not have any vulnerabilities", - "Description": "The latest image in the ECR repository " - + repoName - + " does not have any vulnerabilities reported.", - "Remediation": { - "Recommendation": { - "Text": "Click here to navigate to the ECR Vulnerability console for this image", - "Url": vulnDeepLink, - } - }, - "SourceUrl": vulnDeepLink, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Container", - "Id": repoName + ":" + imageTag, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Container": { - "Name": repoName + ":" + imageTag, - "ImageId": imageDigest, - }, - "Other": { - "RepositoryName": repoName, - "RepositoryArn": repoArn, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.CM-8", - "NIST SP 800-53 RA-5", - "AICPA TSC CC7.1", - "ISO 27001:2013 A.12.6.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - else: - pass diff --git a/auditors/Amazon_ECS_Auditor.py b/auditors/Amazon_ECS_Auditor.py deleted file mode 100644 index 16dd49bd..00000000 --- a/auditors/Amazon_ECS_Auditor.py +++ /dev/null @@ -1,317 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -ecs = boto3.client("ecs") -securityhub = boto3.client("securityhub") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through ECS Clusters -response = ecs.list_clusters() -myEcsClusters = response["clusterArns"] - - -class EcsClusterContainerInsightsCheck(Auditor): - def execute(self): - for clusters in myEcsClusters: - clusterArn = str(clusters) - try: - response = ecs.describe_clusters(clusters=[clusterArn]) - for clusterinfo in response["clusters"]: - clusterName = str(clusterinfo["clusterName"]) - ecsClusterArn = str(clusterinfo["clusterArn"]) - for settings in clusterinfo["settings"]: - contInsightsCheck = str(settings["value"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if contInsightsCheck == "disabled": - finding = { - "SchemaVersion": "2018-10-08", - "Id": ecsClusterArn - + "/ecs-cluster-container-insights-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ecsClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ECS.1] ECS clusters should have container insights enabled", - "Description": "ECS cluster " - + clusterName - + " does not have container insights enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For information on configuring Container Insights for your cluster refer to the Setting Up Container Insights on Amazon ECS for Cluster- and Service-Level Metrics section of the Amazon CloudWatch User Guide", - "Url": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-ECS-cluster.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcsCluster", - "Id": ecsClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"ClusterName": clusterName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ecsClusterArn - + "/ecs-cluster-container-insights-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ecsClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECS.1] ECS clusters should have container insights enabled", - "Description": "ECS cluster " - + clusterName - + " has container insights enabled.", - "Remediation": { - "Recommendation": { - "Text": "For information on configuring Container Insights for your cluster refer to the Setting Up Container Insights on Amazon ECS for Cluster- and Service-Level Metrics section of the Amazon CloudWatch User Guide", - "Url": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-ECS-cluster.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcsCluster", - "Id": ecsClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"ClusterName": clusterName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class EcsClusterDefaultProviderStrategyCheck(Auditor): - def execute(self): - for clusters in myEcsClusters: - clusterArn = str(clusters) - try: - response = ecs.describe_clusters(clusters=[clusterArn]) - for clusterinfo in response["clusters"]: - clusterName = str(clusterinfo["clusterName"]) - ecsClusterArn = str(clusterinfo["clusterArn"]) - defaultProviderStratCheck = str( - clusterinfo["defaultCapacityProviderStrategy"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if defaultProviderStratCheck == "[]": - finding = { - "SchemaVersion": "2018-10-08", - "Id": ecsClusterArn - + "/ecs-cluster-default-provider-strategy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ecsClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECS.2] ECS clusters should have a default cluster capacity provider strategy configured", - "Description": "ECS cluster " - + clusterName - + " does not have a default provider strategy configured. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For information on cluster capacity provider strategies for your cluster refer to the Amazon ECS Cluster Capacity Providers section of the Amazon Elastic Container Service Developer Guide", - "Url": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcsCluster", - "Id": ecsClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ecsClusterArn - + "/ecs-cluster-default-provider-strategy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ecsClusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ECS.2] ECS clusters should have a default cluster capacity provider strategy configured", - "Description": "ECS cluster " - + clusterName - + " has a default provider strategy configured.", - "Remediation": { - "Recommendation": { - "Text": "For information on cluster capacity provider strategies for your cluster refer to the Amazon ECS Cluster Capacity Providers section of the Amazon Elastic Container Service Developer Guide", - "Url": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEcsCluster", - "Id": ecsClusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_EFS_Auditor.py b/auditors/Amazon_EFS_Auditor.py deleted file mode 100644 index 8ea53b93..00000000 --- a/auditors/Amazon_EFS_Auditor.py +++ /dev/null @@ -1,165 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -efs = boto3.client("efs") -sts = boto3.client("sts") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through EFS file systems -response = efs.describe_file_systems() -myFileSys = response["FileSystems"] - - -class EfsFilesysEncryptionCheck(Auditor): - def execute(self): - for filesys in myFileSys: - encryptionCheck = str(filesys["Encrypted"]) - fileSysId = str(filesys["FileSystemId"]) - fileSysArn = ( - "arn:aws:elasticfilesystem:" - + awsRegion - + ":" - + awsAccountId - + ":file-system/" - + fileSysId - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if encryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": fileSysArn + "/efs-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": fileSysArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EFS.1] EFS File Systems should have encryption enabled", - "Description": "EFS file system " - + fileSysId - + " does not have encryption enabled. EFS file systems cannot be encrypted after creation, consider backing up data and creating a new encrypted file system.", - "Remediation": { - "Recommendation": { - "Text": "For EFS encryption information refer to the Data Encryption in EFS section of the Amazon Elastic File System User Guide", - "Url": "https://docs.aws.amazon.com/efs/latest/ug/encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticFileSystem", - "Id": fileSysArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"fileSystemId": fileSysId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": fileSysArn + "/efs-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": fileSysArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EFS.1] EFS File Systems should have encryption enabled", - "Description": "EFS file system " - + fileSysId - + " has encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "For EFS encryption information refer to the Data Encryption in EFS section of the Amazon Elastic File System User Guide", - "Url": "https://docs.aws.amazon.com/efs/latest/ug/encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticFileSystem", - "Id": fileSysArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"fileSystemId": fileSysId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_EKS_Auditor.py b/auditors/Amazon_EKS_Auditor.py deleted file mode 100644 index 23f95674..00000000 --- a/auditors/Amazon_EKS_Auditor.py +++ /dev/null @@ -1,469 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -eks = boto3.client("eks") -securityhub = boto3.client("securityhub") -# create region & account variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] - - -class EksPublicEndpointAccessCheck(Auditor): - def execute(self): - # loop through EKS clusters - response = eks.list_clusters(maxResults=100) - myEksClusters = response["clusters"] - for clusters in myEksClusters: - cluster = str(clusters) - try: - response = eks.describe_cluster(name=cluster) - clusterName = str(response["cluster"]["name"]) - clusterArn = str(response["cluster"]["arn"]) - eksPublicAccessCheck = str( - response["cluster"]["resourcesVpcConfig"]["endpointPublicAccess"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if eksPublicAccessCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/public-endpoint-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[EKS.1] Elastic Kubernetes Service (EKS) cluster API servers should not be accessible from the internet", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " API server is accessible from the internet. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your EKS cluster is not intended to be public refer to the Amazon EKS Cluster Endpoint Access Control section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"Cluster Name": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/public-endpoint-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EKS.1] Elastic Kubernetes Service (EKS) cluster API servers should not be accessible from the internet", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " API server is not accessible from the internet.", - "Remediation": { - "Recommendation": { - "Text": "If your EKS cluster is not intended to be public refer to the Amazon EKS Cluster Endpoint Access Control section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"Cluster Name": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class EksLatestK8sVersionCheck(Auditor): - def execute(self): - # loop through EKS clusters - response = eks.list_clusters(maxResults=100) - myEksClusters = response["clusters"] - for clusters in myEksClusters: - cluster = str(clusters) - try: - response = eks.describe_cluster(name=cluster) - clusterName = str(response["cluster"]["name"]) - clusterArn = str(response["cluster"]["arn"]) - k8sVersionCheck = str(response["cluster"]["version"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if k8sVersionCheck != "1.14" or "1.15": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/eks-latest-k8s-version-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EKS.2] Elastic Kubernetes Service (EKS) clusters should use the latest Kubernetes version", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " is using Kubernetes version " - + k8sVersionCheck - + ". Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "Unless your application requires a specific version of Kubernetes, AWS recommends you choose the latest available Kubernetes version supported by Amazon EKS for your clusters. For upgrade information refer to the Updating an Amazon EKS Cluster Kubernetes Version section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"Cluster Name": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/eks-latest-k8s-version-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EKS.2] Elastic Kubernetes Service (EKS) clusters should use the latest Kubernetes version", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " is using Kubernetes version " - + k8sVersionCheck, - "Remediation": { - "Recommendation": { - "Text": "Unless your application requires a specific version of Kubernetes, AWS recommends you choose the latest available Kubernetes version supported by Amazon EKS for your clusters. For upgrade information refer to the Updating an Amazon EKS Cluster Kubernetes Version section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"Cluster Name": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class EksLoggingAuditAuthCheck(Auditor): - def execute(self): - # loop through EKS clusters - response = eks.list_clusters(maxResults=100) - myEksClusters = response["clusters"] - for clusters in myEksClusters: - cluster = str(clusters) - try: - response = eks.describe_cluster(name=cluster) - clusterName = str(response["cluster"]["name"]) - clusterArn = str(response["cluster"]["arn"]) - logInfo = response["cluster"]["logging"]["clusterLogging"] - for logs in logInfo: - logTypes = logs["types"] - enableCheck = str(logs["enabled"]) - if enableCheck == "True": - for logs in logTypes: - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if str(logs) == "authenticator" and "audit": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/eks-logging-audit-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EKS.3] Elastic Kubernetes Service (EKS) clusters should have authenticator and/or audit logging enabled", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " has authenticator and audit logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "To enable logging for your cluster refer to the Amazon EKS Control Plane Logging section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"Cluster Name": clusterName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/eks-logging-audit-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterName, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EKS.3] Elastic Kubernetes Service (EKS) clusters should have authenticator and/or audit logging enabled", - "Description": "Elastic Kubernetes Service (EKS) cluster " - + clusterName - + " does not have authenticator or audit logging enabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "To enable logging for your cluster refer to the Amazon EKS Control Plane Logging section of the EKS user guide", - "Url": "https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEksCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"Cluster Name": clusterName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_ELB_Auditor.py b/auditors/Amazon_ELB_Auditor.py deleted file mode 100644 index 61a88699..00000000 --- a/auditors/Amazon_ELB_Auditor.py +++ /dev/null @@ -1,769 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# create boto3 clients -sts = boto3.client("sts") -elb = boto3.client("elb") -securityhub = boto3.client("securityhub") -# creat env vars -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] - - -class InternetFacingClbHttpsListenerCheck(Auditor): - def execute(self): - # loop through classic load balancers - response = elb.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - clbScheme = str(classicbalancer["Scheme"]) - if clbScheme == "internet-facing": - for listeners in classicbalancer["ListenerDescriptions"]: - listenerProtocol = str(listeners["Listener"]["Protocol"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if listenerProtocol != "HTTPS" or "SSL": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn - + "/classic-loadbalancer-secure-listener-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ELB.1] Classic load balancers that are internet-facing should use secure listeners", - "Description": "Classic load balancer " - + clbName - + " does not use a secure listener (HTTPS or SSL). Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on classic load balancer HTTPS listeners refer to the Create a Classic Load Balancer with an HTTPS Listener section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-create-https-ssl-load-balancer.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn - + "/classic-loadbalancer-secure-listener-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELB.1] Classic load balancers that are internet-facing should use secure listeners", - "Description": "Classic load balancer " - + clbName - + " uses a secure listener (HTTPS or SSL).", - "Remediation": { - "Recommendation": { - "Text": "For more information on classic load balancer HTTPS listeners refer to the Create a Classic Load Balancer with an HTTPS Listener section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-create-https-ssl-load-balancer.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - print("Ignoring internal CLB") - pass - - -class ClbHttpsListenerTls12PolicyCheck(Auditor): - def execute(self): - # loop through classic load balancers - response = elb.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - for listeners in classicbalancer["ListenerDescriptions"]: - listenerPolicies = str(listeners["PolicyNames"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if listenerPolicies == "[]": - pass - elif listenerPolicies == "ELBSecurityPolicy-TLS-1-2-2017-01": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-tls12-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELB.2] Classic load balancers should use TLS 1.2 listener policies", - "Description": "Classic load balancer " - + clbName - + " does not use a TLS 1.2 listener policy.", - "Remediation": { - "Recommendation": { - "Text": "For more information on classic load balancer listener policies refer to the Predefined SSL Security Policies for Classic Load Balancers section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-tls12-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ELB.2] Classic load balancers should use TLS 1.2 listener policies", - "Description": "Classic load balancer " - + clbName - + " does not use a TLS 1.2 listener policy. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on classic load balancer listener policies refer to the Predefined SSL Security Policies for Classic Load Balancers section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class ClbCrossZoneBalancingCheck(Auditor): - def execute(self): - # loop through classic load balancers - response = elb.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) - crossZoneCheck = str( - response["LoadBalancerAttributes"]["CrossZoneLoadBalancing"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if crossZoneCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-cross-zone-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ELB.3] Classic load balancers should have cross-zone load balancing configured", - "Description": "Classic load balancer " - + clbName - + " does not have cross-zone load balancing configured. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on cross-zone load balancing refer to the Configure Cross-Zone Load Balancing for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-cross-zone-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELB.3] Classic load balancers should have cross-zone load balancing configured", - "Description": "Classic load balancer " - + clbName - + " has cross-zone load balancing configured.", - "Remediation": { - "Recommendation": { - "Text": "For more information on cross-zone load balancing refer to the Configure Cross-Zone Load Balancing for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class ClbConnectionDrainingCheck(Auditor): - def execute(self): - # loop through classic load balancers - response = elb.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) - connectionDrainCheck = str( - response["LoadBalancerAttributes"]["ConnectionDraining"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if connectionDrainCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-connection-draining-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ELB.4] Classic load balancers should have connection draining configured", - "Description": "Classic load balancer " - + clbName - + " does not have connection draining configured. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on connection draining refer to the Configure Connection Draining for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-conn-drain.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-connection-draining-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELB.4] Classic load balancers should have connection draining configured", - "Description": "Classic load balancer " - + clbName - + " does not have connection draining configured.", - "Remediation": { - "Recommendation": { - "Text": "For more information on connection draining refer to the Configure Connection Draining for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-conn-drain.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class ClbAccessLoggingCheck(Auditor): - def execute(self): - # loop through classic load balancers - response = elb.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) - accessLogCheck = str( - response["LoadBalancerAttributes"]["AccessLog"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if accessLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-access-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ELB.5] Classic load balancers should enable access logging", - "Description": "Classic load balancer " - + clbName - + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on access logging refer to the Access Logs for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classic-loadbalancer-access-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELB.5] Classic load balancers should enable access logging", - "Description": "Classic load balancer " - + clbName - + " does not have access logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on access logging refer to the Access Logs for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_ELBv2_Auditor.py b/auditors/Amazon_ELBv2_Auditor.py deleted file mode 100644 index 0835cd05..00000000 --- a/auditors/Amazon_ELBv2_Auditor.py +++ /dev/null @@ -1,1072 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -elbv2 = boto3.client("elbv2") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through ELBv2 load balancers -response = elbv2.describe_load_balancers() -myElbv2LoadBalancers = response["LoadBalancers"] - - -class Elbv2AlbLoggingCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - if elbv2LbType == "application": - try: - response = elbv2.describe_load_balancer_attributes( - LoadBalancerArn=elbv2Arn - ) - elbv2Attributes = response["Attributes"] - for attributes in elbv2Attributes: - if str(attributes["Key"]) == "access_logs.s3.enabled": - elbv2LoggingCheck = str(attributes["Value"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if elbv2LoggingCheck == "false": - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ELBv2.1] Application Load Balancers should have access logging enabled", - "Description": "Application load balancer " - + elbv2Name - + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Access Logs for Your Application Load Balancer section of the Application Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.1] Application and Network Load Balancers should have access logging enabled", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " has access logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Access Logs for Your Application Load Balancer section of the Application Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - except Exception as e: - print(e) - else: - pass - - -class Elbv2DeletionProtectionCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - try: - response = elbv2.describe_load_balancer_attributes( - LoadBalancerArn=elbv2Arn - ) - elbv2Attributes = response["Attributes"] - for attributes in elbv2Attributes: - if str(attributes["Key"]) == "deletion_protection.enabled": - elbv2LoggingCheck = str(attributes["Value"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if elbv2LoggingCheck == "false": - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-deletion-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ELBv2.2] Application and Network Load Balancers should have deletion protection enabled", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " does not have deletion protection enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Deletion Protection section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-deletion-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.2] Application and Network Load Balancers should have deletion protection enabled", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " has deletion protection enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Deletion Protection section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - except Exception as e: - print(e) - - -class Elbv2InternetFacingSecureListenersCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - try: - response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) - myElbv2Listeners = response["Listeners"] - for listeners in myElbv2Listeners: - listenerProtocol = str(listeners["Protocol"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - elbv2Scheme == "internet-facing" - and listenerProtocol != "HTTPS" - or "TLS" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/internet-facing-secure-listeners-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[ELBv2.3] Internet-facing Application and Network Load Balancers should have secure listeners configured", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " does not have a secure listener configured. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Create an HTTPS Listener for Your Application Load Balancer section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/internet-facing-secure-listeners-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.3] Internet-facing Application and Network Load Balancers should have secure listeners configured", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " has a secure listener configured.", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Create an HTTPS Listener for Your Application Load Balancer section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class Elbv2Tls12ListenerPolicyCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - try: - response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) - myElbv2Listeners = response["Listeners"] - for listeners in myElbv2Listeners: - listenerProtocol = str(listeners["Protocol"]) - if listenerProtocol == "HTTPS" or "TLS": - listenerTlsPolicyCheck = str(listeners["SslPolicy"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - listenerTlsPolicyCheck - != "ELBSecurityPolicy-TLS-1-2-2017-01" - or "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" - or "ELBSecurityPolicy-FS-1-2-2019-08" - or "ELBSecurityPolicy-FS-1-2-Res-2019-08" - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/secure-listener-tls12-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[ELBv2.4] Application and Network Load Balancers with HTTPS or TLS listeners should enforce TLS 1.2 policies", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " does not enforce a TLS 1.2 policy. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Security Policies section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/secure-listener-tls12-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.4] Application and Network Load Balancers with HTTPS or TLS listeners should enforce TLS 1.2 policies", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " enforces a TLS 1.2 policy.", - "Remediation": { - "Recommendation": { - "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Security Policies section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - except Exception as e: - print(e) - - -class Elbv2DropInvalidHeaderCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - response = elbv2.describe_load_balancer_attributes(LoadBalancerArn=elbv2Arn) - elbv2Attributes = response["Attributes"] - for attributes in elbv2Attributes: - if ( - str(attributes["Key"]) - == "routing.http.drop_invalid_header_fields.enabled" - ): - elbv2DropInvalidHeaderCheck = str(attributes["Value"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if elbv2DropInvalidHeaderCheck == "false": - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-drop-invalid-header-fields-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ELBv2.5] Application Load Balancers should drop invalid HTTP header fields", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " does not drop invalid HTTP header fields. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on dropping invalid HTTP headers refer to the routing.http.drop_invalid_header_fields.enabled section of the Application Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#load-balancer-attributes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-drop-invalid-header-fields-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.5] Application Load Balancers should drop invalid HTTP header fields", - "Description": "ELB " - + elbv2LbType - + " load balancer " - + elbv2Name - + " drops invalid HTTP header fields.", - "Remediation": { - "Recommendation": { - "Text": "For more information on dropping invalid HTTP headers refer to the routing.http.drop_invalid_header_fields.enabled section of the Application Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#load-balancer-attributes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - }, - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class Elbv2NlbTlsLoggingCheck(Auditor): - def execute(self): - for loadbalancers in myElbv2LoadBalancers: - elbv2Arn = str(loadbalancers["LoadBalancerArn"]) - elbv2Name = str(loadbalancers["LoadBalancerName"]) - elbv2DnsName = str(loadbalancers["DNSName"]) - elbv2LbType = str(loadbalancers["Type"]) - elbv2Scheme = str(loadbalancers["Scheme"]) - elbv2VpcId = str(loadbalancers["VpcId"]) - elbv2IpAddressType = str(loadbalancers["IpAddressType"]) - if elbv2LbType == "network": - try: - response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) - for listeners in response["Listeners"]: - protocolCheck = str(listeners["Protocol"]) - if protocolCheck == "TLS": - try: - response = elbv2.describe_load_balancer_attributes( - LoadBalancerArn=elbv2Arn - ) - elbv2Attributes = response["Attributes"] - for attributes in elbv2Attributes: - if ( - str(attributes["Key"]) - == "access_logs.s3.enabled" - ): - elbv2LoggingCheck = str(attributes["Value"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if elbv2LoggingCheck == "false": - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn - + "/tls-nlb-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ELBv2.6] Network Load Balancers with TLS listeners should have access logging enabled", - "Description": "Network load balancer " - + elbv2Name - + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on Network Load Balancer Access Logging and how to configure it refer to the Access Logs for Your Network Load Balancer section of the Network Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn - + "/tls-nlb-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ELBv2.6] Network Load Balancers with TLS listeners should have access logging enabled", - "Description": "Network load balancer " - + elbv2Name - + " has access logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Network Load Balancer Access Logging and how to configure it refer to the Access Logs for Your Network Load Balancer section of the Network Load Balancers User Guide.", - "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - except Exception as e: - print(e) - else: - pass - except Exception as e: - print(e) - else: - pass diff --git a/auditors/Amazon_EMR_Auditor.py b/auditors/Amazon_EMR_Auditor.py deleted file mode 100644 index 6a066b54..00000000 --- a/auditors/Amazon_EMR_Auditor.py +++ /dev/null @@ -1,1400 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import json -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -emr = boto3.client("emr") -sts = boto3.client("sts") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through non-terminated EMR clusters -try: - response = emr.list_clusters(ClusterStates=["STARTING", "RUNNING", "WAITING"]) - myEmrClusters = response["Clusters"] -except Exception as e: - print(e) - - -class EmrClusterSecurityConfigurationCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - secConfigName = str(response["Cluster"]["SecurityConfiguration"]) - # this is a Passing Check - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-cluster-sec-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.1] EMR Clusters should have a security configuration specified", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on creating and attaching a security configuration refer to the Use Security Configurations to Set Up Cluster Security section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-security-configurations.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.IP-1", - "NIST SP 800-53 CM-2", - "NIST SP 800-53 CM-3", - "NIST SP 800-53 CM-4", - "NIST SP 800-53 CM-5", - "NIST SP 800-53 CM-6", - "NIST SP 800-53 CM-7", - "NIST SP 800-53 CM-9", - "NIST SP 800-53 SA-10", - "AICPA TSC A1.3", - "AICPA TSC CC1.4", - "AICPA TSC CC5.3", - "AICPA TSC CC6.2", - "AICPA TSC CC7.1", - "AICPA TSC CC7.3", - "AICPA TSC CC7.4", - "ISO 27001:2013 A.12.1.2", - "ISO 27001:2013 A.12.5.1", - "ISO 27001:2013 A.12.6.2", - "ISO 27001:2013 A.14.2.2", - "ISO 27001:2013 A.14.2.3", - "ISO 27001:2013 A.14.2.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if str(e) == "'SecurityConfiguration'": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-cluster-sec-policy-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EMR.1] EMR Clusters should have a security configuration specified", - "Description": "EMR Cluster " - + clusterName - + " does not have a security configuration specified. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on creating and attaching a security configuration refer to the Use Security Configurations to Set Up Cluster Security section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-security-configurations.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.IP-1", - "NIST SP 800-53 CM-2", - "NIST SP 800-53 CM-3", - "NIST SP 800-53 CM-4", - "NIST SP 800-53 CM-5", - "NIST SP 800-53 CM-6", - "NIST SP 800-53 CM-7", - "NIST SP 800-53 CM-9", - "NIST SP 800-53 SA-10", - "AICPA TSC A1.3", - "AICPA TSC CC1.4", - "AICPA TSC CC5.3", - "AICPA TSC CC6.2", - "AICPA TSC CC7.1", - "AICPA TSC CC7.3", - "AICPA TSC CC7.4", - "ISO 27001:2013 A.12.1.2", - "ISO 27001:2013 A.12.5.1", - "ISO 27001:2013 A.12.6.2", - "ISO 27001:2013 A.14.2.2", - "ISO 27001:2013 A.14.2.3", - "ISO 27001:2013 A.14.2.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - -class EmrSecurityConfigEncryptionInTransitCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - secConfigName = str(response["Cluster"]["SecurityConfiguration"]) - try: - response = emr.describe_security_configuration(Name=secConfigName) - configData = str(response["SecurityConfiguration"]) - jsonConfig = json.loads(configData) - try: - eitCheck = str( - jsonConfig["EncryptionConfiguration"][ - "EnableInTransitEncryption" - ] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if eitCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-encryption-in-transit-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EMR.2] EMR Cluster security configurations should enforce encryption in transit", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enforce encryption in transit. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption in transit refer to the Encryption in Transit section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-intransit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-encryption-in-transit-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.2] EMR Cluster security configurations should enforce encryption in transit", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that enforces encryption in transit.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption in transit refer to the Encryption in Transit section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-intransit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - except Exception as e: - if str(e) == "'SecurityConfiguration'": - pass - else: - print(e) - - -class EmrSecurityConfigEncryptionAtRestCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - secConfigName = str(response["Cluster"]["SecurityConfiguration"]) - try: - response = emr.describe_security_configuration(Name=secConfigName) - configData = str(response["SecurityConfiguration"]) - jsonConfig = json.loads(configData) - try: - earCheck = str( - jsonConfig["EncryptionConfiguration"][ - "EnableAtRestEncryption" - ] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if earCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn - + "/emr-encryption-at-rest-emrfs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EMR.3] EMR Cluster security configurations should enforce encryption at rest for EMRFS", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enforce encryption at rest for EMRFS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EMRFS refer to the Encryption at Rest for EMRFS Data in Amazon S3 section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-s3", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn - + "/emr-encryption-at-rest-emrfs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.3] EMR Cluster security configurations should enforce encryption at rest for EMRFS", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enforce encryption at rest for EMRFS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EMRFS refer to the Encryption at Rest for EMRFS Data in Amazon S3 section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-s3", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - except Exception as e: - if str(e) == "'SecurityConfiguration'": - pass - else: - print(e) - - -class EmrSecurityConfigConfigEbsEncryptionCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - secConfigName = str(response["Cluster"]["SecurityConfiguration"]) - try: - response = emr.describe_security_configuration(Name=secConfigName) - configData = str(response["SecurityConfiguration"]) - jsonConfig = json.loads(configData) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - ebsEncryptionCheck = str( - jsonConfig["EncryptionConfiguration"][ - "AtRestEncryptionConfiguration" - ]["LocalDiskEncryptionConfiguration"]["EnableEbsEncryption"] - ) - if ebsEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enforce encryption at rest for EBS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that enforces encryption at rest for EBS.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if str(e) == "'LocalDiskEncryptionConfiguration'": - # this is a failing check of a lesser severity - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration that does not have any local disk encryption configured. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - except Exception as e: - print(e) - except Exception as e: - if str(e) == "'SecurityConfiguration'": - pass - else: - print(e) - - -class EmrSecurityConfigKerberosCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - secConfigName = str(response["Cluster"]["SecurityConfiguration"]) - try: - response = emr.describe_security_configuration(Name=secConfigName) - configData = str(response["SecurityConfiguration"]) - jsonConfig = json.loads(configData) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - kerbCheck = str(jsonConfig["AuthenticationConfiguration"]) - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-kerberos-authn-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.5] EMR Cluster security configurations should enable Kerberos authentication", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enable Kerberos authentication. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on Kerberized EMR clusters refer to the Use Kerberos Authentication section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-kerberos.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - "authenticationConfiguration": kerbCheck, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if str(e) == "'AuthenticationConfiguration'": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-kerberos-authn-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EMR.5] EMR Cluster security configurations should enable Kerberos authentication", - "Description": "EMR Cluster " - + clusterName - + " has a security configuration specified that does not enable Kerberos authentication. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "EMR cluster security configurations cannot be specified after creation. For information on Kerberized EMR clusters refer to the Use Kerberos Authentication section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-kerberos.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "securityConfigurationName": secConfigName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - except Exception as e: - print(e) - except Exception as e: - if str(e) == "'SecurityConfiguration'": - pass - else: - print(e) - - -class EmrClusterTerminationProtectionCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - delProtectCheck = str(response["Cluster"]["TerminationProtected"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if delProtectCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-termination-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EMR.6] EMR Clusters should have termination protection enabled", - "Description": "EMR Cluster " - + clusterName - + " does not have termination protection enabled. When termination protection is enabled on a long-running cluster, you can still terminate the cluster, but you must explicitly remove termination protection from the cluster first. This helps ensure that EC2 instances are not shut down by an accident or error. If this configuration is not intentional refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR termination protection refer to the Using Termination Protection section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/UsingEMR_TerminationProtection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-termination-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.6] EMR Clusters should have termination protection enabled", - "Description": "EMR Cluster " - + clusterName - + " has termination protection enabled.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR termination protection refer to the Using Termination Protection section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/UsingEMR_TerminationProtection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class EmrClusterLoggingCheck(Auditor): - def execute(self): - for cluster in myEmrClusters: - clusterId = str(cluster["Id"]) - try: - response = emr.describe_cluster(ClusterId=clusterId) - clusterId = str(response["Cluster"]["Id"]) - clusterName = str(response["Cluster"]["Name"]) - clusterArn = str(response["Cluster"]["ClusterArn"]) - logUriCheck = str(response["Cluster"]["LogUri"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-cluster-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.7] EMR Clusters should have logging enabled", - "Description": "EMR Cluster " - + clusterName - + " does has logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR cluster logging and debugging refer to the Configure Cluster Logging and Debugging section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-debugging.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - "logPathUri": logUriCheck, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if str(e) == "'LogUri'": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/emr-cluster-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[EMR.7] EMR Clusters should have logging enabled", - "Description": "EMR Cluster " - + clusterName - + " does not have logging enabled. You do not need to enable anything to have log files written on the master node. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR cluster logging and debugging refer to the Configure Cluster Logging and Debugging section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-debugging.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEmrCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "clusterId": clusterId, - "clusterName": clusterName, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - -class EmrClusterBlockSecgroupCheck(Auditor): - def execute(self): - try: - response = emr.get_block_public_access_configuration() - blockPubSgCheck = str( - response["BlockPublicAccessConfiguration"][ - "BlockPublicSecurityGroupRules" - ] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if blockPubSgCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/account-level-emr-block-public-sg-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId - + "/" - + awsRegion - + "/" - + "emr-acct-sg-block", - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[EMR.8] EMR account-level public security group access block should be enabled", - "Description": "EMR account-level public security group access block is not enabled for " - + awsAccountId - + " in AWS region " - + awsRegion - + ". Amazon EMR block public access prevents a cluster from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception. Port 22 is an exception by default. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR Block Public Access refer to the Using Amazon EMR Block Public Access section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-block-public-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/account-level-emr-block-public-sg-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId - + "/" - + awsRegion - + "/" - + "emr-acct-sg-block", - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[EMR.8] EMR account-level public security group access block should be enabled", - "Description": "EMR account-level public security group access block is not enabled for " - + awsAccountId - + " in AWS region " - + awsRegion - + ". Amazon EMR block public access prevents a cluster from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception. Port 22 is an exception by default. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", - "Remediation": { - "Recommendation": { - "Text": "For information on EMR Block Public Access refer to the Using Amazon EMR Block Public Access section of the Amazon EMR Management Guide", - "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-block-public-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_Elasticache_Redis_Auditor.py b/auditors/Amazon_Elasticache_Redis_Auditor.py deleted file mode 100644 index 5eaab5f1..00000000 --- a/auditors/Amazon_Elasticache_Redis_Auditor.py +++ /dev/null @@ -1,536 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -elasticache = boto3.client("elasticache") -securityhub = boto3.client("securityhub") -# create env vars for account and region -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] - - -class RedisAuthCheck(Auditor): - def execute(self): - # loop through EC clusters - response = elasticache.describe_cache_clusters(MaxRecords=100) - myElasticacheClusters = response["CacheClusters"] - for clusters in myElasticacheClusters: - clusterId = str(clusters["CacheClusterId"]) - clusterEngine = str(clusters["Engine"]) - # ignore memcached clusters - if clusterEngine != "redis": - pass - else: - engineVersion = str(clusters["EngineVersion"]) - # check for auth token - authTokenCheck = str(clusters["AuthTokenEnabled"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if authTokenCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.1] Elasticache Redis clusters should have an AUTH token enabled", - "Description": "Elasticache cluster " - + clusterId - + " does not have a Redis AUTH token enabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have a Redis AUTH token refer to the Modifying the AUTH Token on an Existing ElastiCache for Redis Cluster section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html#auth-modifyng-token", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.1] Elasticache Redis clusters should have an AUTH token enabled", - "Description": "Elasticache cluster " - + clusterId - + " has a Redis AUTH token enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have a Redis AUTH token refer to the Modifying the AUTH Token on an Existing ElastiCache for Redis Cluster section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html#auth-modifyng-token", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EncryptionAtRestCheck(Auditor): - def execute(self): - # loop through EC clusters - response = elasticache.describe_cache_clusters(MaxRecords=100) - myElasticacheClusters = response["CacheClusters"] - for clusters in myElasticacheClusters: - clusterId = str(clusters["CacheClusterId"]) - clusterEngine = str(clusters["Engine"]) - # ignore memcached clusters - if clusterEngine != "redis": - print( - "Memcached cluster found, skipping as it does not support encryption" - ) - pass - else: - engineVersion = str(clusters["EngineVersion"]) - # check for encryption at rest - atRestEncryptionCheck = str(clusters["AtRestEncryptionEnabled"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if atRestEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.2] Elasticache Redis clusters should have encryption at rest enabled", - "Description": "Elasticache cluster " - + clusterId - + " does not have encryption at rest enabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have encryption at rest enabled refer to the At-Rest Encryption in ElastiCache for Redis section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/at-rest-encryption.html#at-rest-encryption-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.2] Elasticache Redis clusters should have encryption at rest enabled", - "Description": "Elasticache cluster " - + clusterId - + " has encryption at rest enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have encryption at rest enabled refer to the At-Rest Encryption in ElastiCache for Redis section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/at-rest-encryption.html#at-rest-encryption-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EncryptionInTransitCheck(Auditor): - def execute(self): - # loop through EC clusters - response = elasticache.describe_cache_clusters(MaxRecords=100) - myElasticacheClusters = response["CacheClusters"] - for clusters in myElasticacheClusters: - clusterId = str(clusters["CacheClusterId"]) - clusterEngine = str(clusters["Engine"]) - # ignore memcached clusters - if clusterEngine != "redis": - print( - "Memcached cluster found, skipping as it does not support encryption" - ) - pass - else: - engineVersion = str(clusters["EngineVersion"]) - # check for encryption in transit - inTransitEncryptionCheck = str(clusters["TransitEncryptionEnabled"]) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if inTransitEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.3] Elasticache Redis clusters should have encryption in transit enabled", - "Description": "Elasticache cluster " - + clusterId - + " does not have encryption in transit enabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have encryption in transit enabled refer to the Enabling In-Transit Encryption section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#in-transit-encryption-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterId + "/no-redis-auth-token", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticache.Redis.3] Elasticache Redis clusters should have encryption in transit enabled", - "Description": "Elasticache cluster " - + clusterId - + " has encryption in transit enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have encryption in transit enabled refer to the Enabling In-Transit Encryption section of the ElastiCache for Redis User Guide", - "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#in-transit-encryption-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElastiCacheCacheCluster", - "Id": "arn:aws:elasticache:" - + awsRegion - + ":" - + awsAccountId - + ":cluster:" - + clusterId, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ClusterId": clusterId, - "EngineVersion": engineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_ElasticsearchService_Auditor.py b/auditors/Amazon_ElasticsearchService_Auditor.py deleted file mode 100644 index 549e8608..00000000 --- a/auditors/Amazon_ElasticsearchService_Auditor.py +++ /dev/null @@ -1,1157 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -elasticsearch = boto3.client("es") -securityhub = boto3.client("securityhub") -# create env vars for account and region -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through elasticsearch domains -response = elasticsearch.list_domain_names() -myDomainNames = response["DomainNames"] - - -class DedicatedMasterCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - dedicatedMasterCheck = str( - response["DomainStatus"]["ElasticsearchClusterConfig"][ - "DedicatedMasterEnabled" - ] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if dedicatedMasterCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-dedicated-master-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[Elasticsearch.1] Elasticsearch Service domains should use dedicated master nodes", - "Description": "Elasticsearch Service domain " - + esDomainName - + " does not use dedicated master nodes. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your domain should dedicated master nodes enabled refer to the Configuring Amazon ES Domains section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains-configure-cluster", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-dedicated-master-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.1] Elasticsearch Service domains should use dedicated master nodes", - "Description": "Elasticsearch Service domain " - + esDomainName - + " uses dedicated master nodes.", - "Remediation": { - "Recommendation": { - "Text": "If your domain should dedicated master nodes enabled refer to the Configuring Amazon ES Domains section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains-configure-cluster", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class CognitoCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - cognitoEnabledCheck = str( - response["DomainStatus"]["CognitoOptions"]["Enabled"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if cognitoEnabledCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-cognito-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Elasticsearch.2] Elasticsearch Service domains should use Cognito authentication for Kibana", - "Description": "Elasticsearch Service domain " - + esDomainName - + " does not use Cognito authentication for Kibana. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your domain should use Cognito authentication for Kibana refer to the Amazon Cognito Authentication for Kibana section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-cognito-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.2] Elasticsearch Service domains should use Cognito authentication for Kibana", - "Description": "Elasticsearch Service domain " - + esDomainName - + " uses Cognito authentication for Kibana.", - "Remediation": { - "Recommendation": { - "Text": "If your domain should use Cognito authentication for Kibana refer to the Amazon Cognito Authentication for Kibana section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class EncryptionAtRestCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - encryptionAtRestCheck = str( - response["DomainStatus"]["EncryptionAtRestOptions"]["Enabled"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if encryptionAtRestCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-encryption-at-rest-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticsearch.3] Elasticsearch Service domains should be encrypted at rest", - "Description": "Elasticsearch Service domain " - + esDomainName - + " is not encrypted at rest. You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later", - "Remediation": { - "Recommendation": { - "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later.", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html#enabling-ear", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "EncryptionAtRestOptions": {"Enabled": False}, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-encryption-at-rest-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.3] Elasticsearch Service domains should be encrypted at rest", - "Description": "Elasticsearch Service domain " - + esDomainName - + " is encrypted at rest", - "Remediation": { - "Recommendation": { - "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later.", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html#enabling-ear", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "EncryptionAtRestOptions": {"Enabled": True}, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class Node2nodeEncryptionCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - node2nodeEncryptionCheck = str( - response["DomainStatus"]["NodeToNodeEncryptionOptions"]["Enabled"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if node2nodeEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-node2node-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticsearch.4] Elasticsearch Service domains should use node-to-node encryption", - "Description": "Elasticsearch Service domain " - + esDomainName - + " does not use node-to-node encryption. You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later", - "Remediation": { - "Recommendation": { - "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later.", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ntn.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "NodeToNodeEncryptionOptions": {"Enabled": False}, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-node2node-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.4] Elasticsearch Service domains should use node-to-node encryption", - "Description": "Elasticsearch Service domain " - + esDomainName - + " uses node-to-node encryption.", - "Remediation": { - "Recommendation": { - "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later.", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ntn.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "NodeToNodeEncryptionOptions": {"Enabled": True}, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class HttpsEnforcementCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - httpsEnforcementCheck = str( - response["DomainStatus"]["DomainEndpointOptions"]["EnforceHTTPS"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if httpsEnforcementCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-enforce-https-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticsearch.5] Elasticsearch Service domains should enforce HTTPS-only communications", - "Description": "Elasticsearch Service domain " - + esDomainName - + " does not enforce HTTPS-only communications. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your domain should enforce HTTPS-only communications refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "DomainEndpointOptions": {"EnforceHTTPS": False}, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-enforce-https-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.5] Elasticsearch Service domains should enforce HTTPS-only communications", - "Description": "Elasticsearch Service domain " - + esDomainName - + " enforces HTTPS-only communications. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your domain should enforce HTTPS-only communications refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "DomainEndpointOptions": {"EnforceHTTPS": True}, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class TlsPolicyCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - httpsEnforcementCheck = str( - response["DomainStatus"]["DomainEndpointOptions"]["EnforceHTTPS"] - ) - if httpsEnforcementCheck == "True": - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - tlsPolicyCheck = str( - response["DomainStatus"]["DomainEndpointOptions"][ - "TLSSecurityPolicy" - ] - ) - if tlsPolicyCheck != "Policy-Min-TLS-1-2-2019-07": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-tls-1-2-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Elasticsearch.6] Elasticsearch Service domains that enforce HTTPS-only communications should use a TLS 1.2 security policy", - "Description": "Elasticsearch Service domain " - + esDomainName - + " does not use a TLS 1.2 security policy. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your domain should use a TLS 1.2 security policy refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "DomainEndpointOptions": { - "EnforceHTTPS": True, - "TLSSecurityPolicy": tlsPolicyCheck, - }, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-tls-1-2-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.6] Elasticsearch Service domains that enforce HTTPS-only communications should use a TLS 1.2 security policy", - "Description": "Elasticsearch Service domain " - + esDomainName - + " uses a TLS 1.2 security policy.", - "Remediation": { - "Recommendation": { - "Text": "If your domain should use a TLS 1.2 security policy refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "DomainEndpointOptions": { - "EnforceHTTPS": True, - "TLSSecurityPolicy": tlsPolicyCheck, - }, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class ElasticUpdateCheck(Auditor): - def execute(self): - for domains in myDomainNames: - esDomainName = str(domains["DomainName"]) - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomainName - ) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - domainId = str(response["DomainStatus"]["DomainId"]) - domainArn = str(response["DomainStatus"]["ARN"]) - updateCheck = str( - response["DomainStatus"]["ServiceSoftwareOptions"]["UpdateAvailable"] - ) - updateInformation = str( - response["DomainStatus"]["ServiceSoftwareOptions"]["Description"] - ) - # ISO Time - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if updateCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-enforce-https-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[Elasticsearch.7] Elasticsearch Service domains should be updated to the latest service software version", - "Description": "Elasticsearch Service domain " - + esDomainName - + " is not up to date. Service provided message follows: " - + updateInformation - + ". Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For update information refer to the Service Software Updates section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-service-software", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.MA-1", - "NIST SP 800-53 MA-2", - "NIST SP 800-53 MA-3", - "NIST SP 800-53 MA-5", - "NIST SP 800-53 MA-6", - "AICPA TSC CC8.1", - "ISO 27001:2013 A.11.1.2", - "ISO 27001:2013 A.11.2.4", - "ISO 27001:2013 A.11.2.5", - "ISO 27001:2013 A.11.2.6", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": domainArn + "/elasticsearch-enforce-https-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": domainArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Elasticsearch.7] Elasticsearch Service domains should be updated to the latest service software version", - "Description": "Elasticsearch Service domain " - + esDomainName - + " is up to date. Service provided message follows: " - + updateInformation, - "Remediation": { - "Recommendation": { - "Text": "For update information refer to the Service Software Updates section of the Amazon Elasticsearch Service Developer Guide", - "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-service-software", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": domainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": domainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.MA-1", - "NIST SP 800-53 MA-2", - "NIST SP 800-53 MA-3", - "NIST SP 800-53 MA-5", - "NIST SP 800-53 MA-6", - "AICPA TSC CC8.1", - "ISO 27001:2013 A.11.1.2", - "ISO 27001:2013 A.11.2.4", - "ISO 27001:2013 A.11.2.5", - "ISO 27001:2013 A.11.2.6", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_Kinesis_Data_Streams_Auditor.py b/auditors/Amazon_Kinesis_Data_Streams_Auditor.py deleted file mode 100644 index fe3fbff2..00000000 --- a/auditors/Amazon_Kinesis_Data_Streams_Auditor.py +++ /dev/null @@ -1,296 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -kinesis = boto3.client("kinesis") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through kinesis streams -response = kinesis.list_streams(Limit=100) -myKinesisStreams = response["StreamNames"] - - -class KinesisStreamEncryptionCheck(Auditor): - def execute(self): - for streams in myKinesisStreams: - response = kinesis.describe_stream(StreamName=streams) - streamArn = str(response["StreamDescription"]["StreamARN"]) - streamName = str(response["StreamDescription"]["StreamName"]) - streamEncryptionCheck = str(response["StreamDescription"]["EncryptionType"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if streamEncryptionCheck == "NONE": - finding = { - "SchemaVersion": "2018-10-08", - "Id": streamArn + "/kinesis-streams-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": streamArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Kinesis.1] Kinesis Data Streams should be encrypted", - "Description": "Kinesis data stream " - + streamName - + " is not encrypted. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Data Stream encryption refer to the How Do I Get Started with Server-Side Encryption? section of the Amazon Kinesis Data Streams Developer Guide", - "Url": "https://docs.aws.amazon.com/streams/latest/dev/getting-started-with-sse.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisStream", - "Id": streamArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"StreamName": streamName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": streamArn + "/kinesis-streams-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": streamArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Kinesis.1] Kinesis Data Streams should be encrypted", - "Description": "Kinesis data stream " - + streamName - + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Data Stream encryption refer to the How Do I Get Started with Server-Side Encryption? section of the Amazon Kinesis Data Streams Developer Guide", - "Url": "https://docs.aws.amazon.com/streams/latest/dev/getting-started-with-sse.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisStream", - "Id": streamArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"StreamName": streamName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class KinesisEnhancedMonitoringCheck(Auditor): - def execute(self): - for streams in myKinesisStreams: - response = kinesis.describe_stream(StreamName=streams) - streamArn = str(response["StreamDescription"]["StreamARN"]) - streamName = str(response["StreamDescription"]["StreamName"]) - streamEnhancedMonitoring = response["StreamDescription"][ - "EnhancedMonitoring" - ] - for enhancedmonitors in streamEnhancedMonitoring: - shardLevelMetricCheck = str(enhancedmonitors["ShardLevelMetrics"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if shardLevelMetricCheck == "[]": - finding = { - "SchemaVersion": "2018-10-08", - "Id": streamArn + "/kinesis-streams-enhanced-monitoring-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": streamArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[Kinesis.2] Business-critical Kinesis Data Streams should have detailed monitoring configured", - "Description": "Kinesis data stream " - + streamName - + " does not have detailed monitoring configured, detailed monitoring allows shard-level metrics to be delivered every minute at additional cost. Business-critical streams should be considered for this configuration. Refer to the remediation instructions for information on this configuration", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Data Stream enhanced monitoring refer to the Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch section of the Amazon Kinesis Data Streams Developer Guide", - "Url": "https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisStream", - "Id": streamArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"StreamName": streamName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": streamArn + "/kinesis-streams-enhanced-monitoring-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": streamArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Kinesis.2] Business-critical Kinesis Data Streams should have detailed monitoring configured", - "Description": "Kinesis data stream " - + streamName - + " has detailed monitoring configured.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Data Stream enhanced monitoring refer to the Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch section of the Amazon Kinesis Data Streams Developer Guide", - "Url": "https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisStream", - "Id": streamArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"StreamName": streamName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_Kinesis_Firehose_Auditor.py b/auditors/Amazon_Kinesis_Firehose_Auditor.py deleted file mode 100644 index e8edf576..00000000 --- a/auditors/Amazon_Kinesis_Firehose_Auditor.py +++ /dev/null @@ -1,176 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -firehose = boto3.client("firehose") -securityhub = boto3.client("securityhub") -# create region & account variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through Firehose delivery streams -try: - response = firehose.list_delivery_streams(Limit=100) - myFirehoseStreams = response["DeliveryStreamNames"] -except Exception as e: - print(e) - - -class FirehoseDeliveryStreamEncryptionCheck(Auditor): - def execute(self): - for deliverystreams in myFirehoseStreams: - firehoseName = str(deliverystreams) - try: - response = firehose.describe_delivery_stream( - DeliveryStreamName=firehoseName - ) - firehoseArn = str(response["DeliveryStreamARN"]) - firehoseEncryptionCheck = str( - response["DeliveryStreamDescription"][ - "DeliveryStreamEncryptionConfiguration" - ]["Status"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if firehoseEncryptionCheck == "DISABLED": - finding = { - "SchemaVersion": "2018-10-08", - "Id": firehoseArn + "/firehose-stream-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": firehoseArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Firehose.1] AWS Kinesis Firehose delivery streams should be encrypted", - "Description": "AWS Kinesis Firehose delivery stream " - + firehoseName - + " is not encrypted. If you send data to your delivery stream using PutRecord or PutRecordBatch, or if you send the data using AWS IoT, Amazon CloudWatch Logs, or CloudWatch Events, you can turn on server-side encryption by using the StartDeliveryStreamEncryption operation. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Firehose encryption refer to the Data Protection in Amazon Kinesis Data Firehose section of the Amazon Kinesis Data Firehose Developer Guide", - "Url": "https://docs.aws.amazon.com/firehose/latest/dev/encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisFirehoseDeliveryStream", - "Id": firehoseArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"deliveryStreamName": firehoseName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - elif firehoseEncryptionCheck == "ENABLED": - finding = { - "SchemaVersion": "2018-10-08", - "Id": firehoseArn + "/firehose-stream-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": firehoseArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Firehose.1] AWS Kinesis Firehose delivery streams should be encrypted", - "Description": "AWS Kinesis Firehose delivery stream " - + firehoseName - + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Kinesis Firehose encryption refer to the Data Protection in Amazon Kinesis Data Firehose section of the Amazon Kinesis Data Firehose Developer Guide", - "Url": "https://docs.aws.amazon.com/firehose/latest/dev/encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsKinesisFirehoseDeliveryStream", - "Id": firehoseArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"deliveryStreamName": firehoseName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - except Exception as e: - print(e) diff --git a/auditors/Amazon_MQ_Auditor.py b/auditors/Amazon_MQ_Auditor.py deleted file mode 100644 index 4f5a029a..00000000 --- a/auditors/Amazon_MQ_Auditor.py +++ /dev/null @@ -1,773 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -securityhub = boto3.client("securityhub") -amzmq = boto3.client("mq") -sts = boto3.client("sts") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through Amazon MQ Brokers -try: - response = amzmq.list_brokers(MaxResults=100) - myBrokers = response["BrokerSummaries"] -except Exception as e: - print(e) - - -class BrokerKmsCmkCheck(Auditor): - def execute(self): - for broker in myBrokers: - brokerName = str(broker["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - kmsCmkCheck = str(response["EncryptionOptions"]["UseAwsOwnedKey"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if kmsCmkCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-kms-cmk-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AmazonMQ.1] AmazonMQ message brokers should use customer-managed KMS CMKs for encryption", - "Description": "AmazonMQ broker " - + brokerName - + " does not use a customer-managed KMS CMK for encryption. Customer managed CMKs are CMKs in your AWS account that you create, own, and manage. You have full control over these CMKs, including establishing and maintaining their key policies, IAM policies, and grants, enabling and disabling them, rotating their cryptographic material, adding tags, creating aliases that refer to the CMK, and scheduling the CMKs for deletion. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on encryption at rest considerations for Amazon MQ refer to the Encryption at Rest section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-encryption.html#encryption-at-rest", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - kmsKeyId = str(response["EncryptionOptions"]["KmsKeyId"]) - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-kms-cmk-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.1] AmazonMQ message brokers should use customer-managed KMS CMKs for encryption", - "Description": "AmazonMQ broker " - + brokerName - + " uses a customer-managed KMS CMK for encryption.", - "Remediation": { - "Recommendation": { - "Text": "For more information on encryption at rest considerations for Amazon MQ refer to the Encryption at Rest section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-encryption.html#encryption-at-rest", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - "kmsKeyId": kmsKeyId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class BrokerAuditLoggingCheck(Auditor): - def execute(self): - for broker in myBrokers: - brokerName = str(broker["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - auditLogCheck = str(response["Logs"]["Audit"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if auditLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AmazonMQ.2] AmazonMQ message brokers should have audit logging enabled", - "Description": "AmazonMQ broker " - + brokerName - + " does not have audit logging enabled. Audit logging enables logging of management actions taken using JMX or using the ActiveMQ Web Console and publishes audit.log to a log group in CloudWatch. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.2] AmazonMQ message brokers should have audit logging enabled", - "Description": "AmazonMQ broker " - + brokerName - + " has audit logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class BrokerGeneralLoggingCheck(Auditor): - def execute(self): - for broker in myBrokers: - brokerName = str(broker["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - genLogCheck = str(response["Logs"]["General"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if genLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-general-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AmazonMQ.3] AmazonMQ message brokers should have general logging enabled", - "Description": "AmazonMQ broker " - + brokerName - + " does not have general logging enabled. General logging enables the default INFO logging level (DEBUG logging isnt supported) and publishes activemq.log to a log group in CloudWatch. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-broker-general-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.3] AmazonMQ message brokers should have general logging enabled", - "Description": "AmazonMQ broker " - + brokerName - + " has general logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class BrokerPublicAccessCheck(Auditor): - def execute(self): - for broker in myBrokers: - brokerName = str(broker["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - publicAccessCheck = str(response["PubliclyAccessible"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if publicAccessCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-public-accessible-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.4] AmazonMQ message brokers should not be publicly accessible", - "Description": "AmazonMQ broker " - + brokerName - + " is publicly accessible. Brokers created without public accessibility cannot be accessed from outside of your VPC. This greatly reduces your susceptibility to Distributed Denial of Service (DDoS) attacks from the public internet. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker accessibility through a VPC refer to the Accessing the ActiveMQ Web Console of a Broker without Public Accessibility section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/accessing-web-console-of-broker-without-private-accessibility.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-public-accessible-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.4] AmazonMQ message brokers should not be publicly accessible", - "Description": "AmazonMQ broker " - + brokerName - + " is not publicly accessible.", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker accessibility through a VPC refer to the Accessing the ActiveMQ Web Console of a Broker without Public Accessibility section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/accessing-web-console-of-broker-without-private-accessibility.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class BrokerMinorVersionAutoUpgradeCheck(Auditor): - def execute(self): - for broker in myBrokers: - brokerName = str(broker["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - autoUpgrMinorVersionCheck = str(response["AutoMinorVersionUpgrade"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if autoUpgrMinorVersionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-auto-minor-version-upgrade-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AmazonMQ.5] AmazonMQ message brokers should be configured to automatically upgrade to the latest minor version", - "Description": "AmazonMQ broker " - + brokerName - + " is not configured to automatically upgrade to the latest minor version. To upgrade the broker to new versions as AWS releases them, choose Enable automatic minor version upgrades. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker auto upgrades refer to the Tutorial: Editing Broker Engine Version, Instance Type, CloudWatch Logs, and Maintenance Preferences section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-editing-broker-preferences.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.MA-1", - "NIST SP 800-53 MA-2", - "NIST SP 800-53 MA-3", - "NIST SP 800-53 MA-5", - "NIST SP 800-53 MA-6", - "AICPA TSC CC8.1", - "ISO 27001:2013 A.11.1.2", - "ISO 27001:2013 A.11.2.4", - "ISO 27001:2013 A.11.2.5", - "ISO 27001:2013 A.11.2.6", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn + "/amazonmq-auto-minor-version-upgrade-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AmazonMQ.5] AmazonMQ message brokers should be configured to automatically upgrade to the latest minor version", - "Description": "AmazonMQ broker " - + brokerName - + " is configured to automatically upgrade to the latest minor version.", - "Remediation": { - "Recommendation": { - "Text": "For more information on message broker auto upgrades refer to the Tutorial: Editing Broker Engine Version, Instance Type, CloudWatch Logs, and Maintenance Preferences section of the Amazon MQ Developer Guide", - "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-editing-broker-preferences.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.MA-1", - "NIST SP 800-53 MA-2", - "NIST SP 800-53 MA-3", - "NIST SP 800-53 MA-5", - "NIST SP 800-53 MA-6", - "AICPA TSC CC8.1", - "ISO 27001:2013 A.11.1.2", - "ISO 27001:2013 A.11.2.4", - "ISO 27001:2013 A.11.2.5", - "ISO 27001:2013 A.11.2.6", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) diff --git a/auditors/Amazon_MSK_Auditor.py b/auditors/Amazon_MSK_Auditor.py deleted file mode 100644 index aff7f208..00000000 --- a/auditors/Amazon_MSK_Auditor.py +++ /dev/null @@ -1,577 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -kafka = boto3.client("kafka") -securityhub = boto3.client("securityhub") -# create env vars for account and region -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through managed kafka clusters -response = kafka.list_clusters() -myMskClusters = response["ClusterInfoList"] - - -class InterClusterEncryptionInTransitCheck(Auditor): - def execute(self): - for clusters in myMskClusters: - clusterArn = str(clusters["ClusterArn"]) - clusterName = str(clusters["ClusterName"]) - interClusterEITCheck = str( - clusters["EncryptionInfo"]["EncryptionInTransit"]["InCluster"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if interClusterEITCheck != "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/intercluster-encryption-in-transit", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[MSK.1] Managed Kafka Stream clusters should have inter-cluster encryption in transit enabled", - "Description": "MSK cluster " - + clusterName - + " does not have inter-cluster encryption in transit enabled. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have inter-cluster encryption in transit enabled refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/intercluster-encryption-in-transit", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[MSK.1] Managed Kafka Stream clusters should have inter-cluster encryption in transit enabled", - "Description": "MSK cluster " - + clusterName - + " has inter-cluster encryption in transit enabled.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should have inter-cluster encryption in transit enabled refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class ClientBrokerEncryptionInTransitCheck(Auditor): - def execute(self): - for clusters in myMskClusters: - clusterArn = str(clusters["ClusterArn"]) - clusterName = str(clusters["ClusterName"]) - clientBrokerTlsCheck = str( - clusters["EncryptionInfo"]["EncryptionInTransit"]["ClientBroker"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if clientBrokerTlsCheck != "TLS": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/client-broker-tls", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[MSK.2] Managed Kafka Stream clusters should enforce TLS-only communications between clients and brokers", - "Description": "MSK cluster " - + clusterName - + " does not enforce TLS-only communications between clients and brokers. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should enforce TLS-only communications between clients and brokers refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/client-broker-tls", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[MSK.2] Managed Kafka Stream clusters should enforce TLS-only communications between clients and brokers", - "Description": "MSK cluster " - + clusterName - + " enforces TLS-only communications between clients and brokers", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should enforce TLS-only communications between clients and brokers refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class ClientAuthenticationCheck(Auditor): - def execute(self): - for clusters in myMskClusters: - clusterArn = str(clusters["ClusterArn"]) - clusterName = str(clusters["ClusterName"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - clientAuthCheck = str( - clusters["ClientAuthentication"]["Tls"][ - "CertificateAuthorityArnList" - ] - ) - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/tls-client-auth", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[MSK.3] Managed Kafka Stream clusters should use TLS for client authentication", - "Description": "MSK cluster " - + clusterName - + " uses TLS for client authentication.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should use TLS for client authentication refer to the Client Authentication section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/tls-client-auth", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[MSK.3] Managed Kafka Stream clusters should use TLS for client authentication", - "Description": "MSK cluster " - + clusterName - + " does not use TLS for client authentication. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should use TLS for client authentication refer to the Client Authentication section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class ClusterEnhancedMonitoringCheck(Auditor): - def execute(self): - for clusters in myMskClusters: - clusterArn = str(clusters["ClusterArn"]) - clusterName = str(clusters["ClusterName"]) - enhancedMonitoringCheck = str(clusters["EnhancedMonitoring"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if enhancedMonitoringCheck == "DEFAULT": - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/detailed-monitoring", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[MSK.4] Managed Kafka Stream clusters should use enhanced monitoring", - "Description": "MSK cluster " - + clusterName - + " does not use enhanced monitoring. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should use enhanced monitoring refer to the Monitoring an Amazon MSK Cluster section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/monitoring.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clusterArn + "/detailed-monitoring", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clusterArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[MSK.4] Managed Kafka Stream clusters should use enhanced monitoring", - "Description": "MSK cluster " - + clusterName - + " uses enhanced monitoring.", - "Remediation": { - "Recommendation": { - "Text": "If your cluster should use enhanced monitoring refer to the Monitoring an Amazon MSK Cluster section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", - "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/monitoring.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedKafkaCluster", - "Id": clusterArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"ClusterName": clusterName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - diff --git a/auditors/Amazon_Managed_Blockchain_Auditor.py b/auditors/Amazon_Managed_Blockchain_Auditor.py deleted file mode 100644 index 35820f42..00000000 --- a/auditors/Amazon_Managed_Blockchain_Auditor.py +++ /dev/null @@ -1,564 +0,0 @@ -import boto3 -import datetime -import os -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -amb = boto3.client("managedblockchain") -securityhub = boto3.client("securityhub") -# create account id & region variables -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -# loop through AMB Fabric networks -try: - response = amb.list_networks(Framework="HYPERLEDGER_FABRIC") - myFabricNetworks = response["Networks"] -except Exception as e: - print(e) - - -class AmbFabricNodeChaincodeLoggingCheck(Auditor): - def execute(self): - for networks in myFabricNetworks: - fabricNetworkId = str(networks["Id"]) - try: - response = amb.list_members( - NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True - ) - for members in response["Members"]: - memberId = str(members["Id"]) - try: - response = amb.list_nodes( - NetworkId=fabricNetworkId, - MemberId=memberId, - Status="AVAILABLE", - ) - for nodes in response["Nodes"]: - peerNodeId = str(nodes["Id"]) - try: - response = amb.get_node( - NetworkId=fabricNetworkId, - MemberId=memberId, - NodeId=peerNodeId, - ) - nodeArn = ( - "arn:aws:managedblockchain:" - + awsRegion - + ":" - + awsAccountId - + ":nodes/" - + peerNodeId - ) - chaincodeLogCheck = str( - response["Node"]["LogPublishingConfiguration"][ - "Fabric" - ]["ChaincodeLogs"]["Cloudwatch"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if chaincodeLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": nodeArn - + "/managedblockchain-fabric-node-chaincode-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": nodeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AMB.Fabric.1] Amazon Managed Blockchain Fabric peer nodes should have chaincode logging enabled", - "Description": "Amazon Managed Blockchain Fabric peer node " - + peerNodeId - + " does not have chaincode logging enabled. Chaincode logs help you analyze and debug the business logic and execution of chaincode on a peer node. They contain the results of instantiating, invoking, and querying the chaincode. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsManagedBlockchainPeerNode", - "Id": nodeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - "nodeId": peerNodeId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": nodeArn - + "/managedblockchain-fabric-node-chaincode-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": nodeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AMB.Fabric.1] Amazon Managed Blockchain Fabric peer nodes should have chaincode logging enabled", - "Description": "Amazon Managed Blockchain Fabric peer node " - + peerNodeId - + " has chaincode logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsManagedBlockchainPeerNode", - "Id": nodeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - "nodeId": peerNodeId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - except Exception as e: - print(e) - - -class AmbFabricNodePeernodeLoggingCheck(Auditor): - def execute(self): - for networks in myFabricNetworks: - fabricNetworkId = str(networks["Id"]) - try: - response = amb.list_members( - NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True - ) - for members in response["Members"]: - memberId = str(members["Id"]) - try: - response = amb.list_nodes( - NetworkId=fabricNetworkId, - MemberId=memberId, - Status="AVAILABLE", - ) - for nodes in response["Nodes"]: - peerNodeId = str(nodes["Id"]) - try: - response = amb.get_node( - NetworkId=fabricNetworkId, - MemberId=memberId, - NodeId=peerNodeId, - ) - nodeArn = ( - "arn:aws:managedblockchain:" - + awsRegion - + ":" - + awsAccountId - + ":nodes/" - + peerNodeId - ) - peerNodeLogCheck = str( - response["Node"]["LogPublishingConfiguration"][ - "Fabric" - ]["PeerLogs"]["Cloudwatch"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if peerNodeLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": nodeArn - + "/managedblockchain-fabric-node-peernode-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": nodeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AMB.Fabric.2] Amazon Managed Blockchain Fabric peer nodes should have peer node logging enabled", - "Description": "Amazon Managed Blockchain Fabric peer node " - + peerNodeId - + " does not have peer node logging enabled. Peer node logs help you debug timeout errors associated with proposals and identify rejected proposals that do not meet the endorsement policies. Peer node logs contain messages generated when your client submits transaction proposals to peer nodes, requests to join channels, enrolls an admin peer, and lists the chaincode instances on a peer node. Peer node logs also contain the results of chaincode installation. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsManagedBlockchainPeerNode", - "Id": nodeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - "nodeId": peerNodeId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": nodeArn - + "/managedblockchain-fabric-node-peernode-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": nodeArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AMB.Fabric.2] Amazon Managed Blockchain Fabric peer nodes should have peer node logging enabled", - "Description": "Amazon Managed Blockchain Fabric peer node " - + peerNodeId - + " has peer node logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": { - "Product Name": "ElectricEye" - }, - "Resources": [ - { - "Type": "AwsManagedBlockchainPeerNode", - "Id": nodeArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - "nodeId": peerNodeId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) - except Exception as e: - print(e) - - -class AmbFabricMemberCaLoggingCheck(Auditor): - def execute(self): - for networks in myFabricNetworks: - fabricNetworkId = str(networks["Id"]) - try: - response = amb.list_members( - NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True - ) - for members in response["Members"]: - memberId = str(members["Id"]) - try: - response = amb.get_member( - NetworkId=fabricNetworkId, MemberId=memberId - ) - memberArn = ( - "arn:aws:managedblockchain:" - + awsRegion - + ":" - + awsAccountId - + ":members/" - + memberId - ) - memberCaLogCheck = str( - response["Member"]["LogPublishingConfiguration"]["Fabric"][ - "CaLogs" - ]["Cloudwatch"]["Enabled"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if memberCaLogCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": memberArn - + "/managedblockchain-member-ca-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": memberArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[AMB.Fabric.3] Amazon Managed Blockchain Fabric members should have certificate authority (CA) logging enabled", - "Description": "Amazon Managed Blockchain Fabric member " - + memberId - + " does not have certificate authority (CA) logging enabled. CA logs help you determine when a member in your account joins the network, or when new peers register with a member CA. You can use CA logs to debug problems related to certificates and enrollment. CA logging can be enabled and disabled for each member. A single log stream for the CA exists for each member. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedBlockchainMember", - "Id": memberArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": memberArn - + "/managedblockchain-member-ca-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": memberArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[AMB.Fabric.3] Amazon Managed Blockchain Fabric members should have certificate authority (CA) logging enabled", - "Description": "Amazon Managed Blockchain Fabric member " - + memberId - + " has certificate authority (CA) logging enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", - "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsManagedBlockchainMember", - "Id": memberArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "networkId": fabricNetworkId, - "memberId": memberId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print(e) diff --git a/auditors/Amazon_Neptune_Auditor.py b/auditors/Amazon_Neptune_Auditor.py deleted file mode 100644 index 127fa9e9..00000000 --- a/auditors/Amazon_Neptune_Auditor.py +++ /dev/null @@ -1,750 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -neptune = boto3.client("neptune") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through neptune instances -neptune_instances = neptune.describe_db_instances( - Filters=[{"Name": "engine", "Values": ["neptune"]}] -) - - -class NeptuneInstanceMultiAzCheck(Auditor): - def execute(self): - for instances in neptune_instances["DBInstances"]: - neptuneInstanceArn = str(instances["DBInstanceArn"]) - neptuneDbId = str(instances["DBInstanceIdentifier"]) - mutliAzCheck = str(instances["MultiAZ"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if mutliAzCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn + "/neptune-instance-ha-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[Neptune.1] Neptune database instances should be configured to be highly available", - "Description": "Neptune database instance " - + neptuneDbId - + " does not have Multi-AZ enabled and thus is not highly available. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune High Availability and how to configure it refer to the High Availability for Neptune section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/feature-overview-availability.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn + "/neptune-instance-ha-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Neptune.1] Neptune database instances should be configured to be highly available", - "Description": "Neptune database instance " - + neptuneDbId - + " is highly available.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune High Availability and how to configure it refer to the High Availability for Neptune section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/feature-overview-availability.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class NeptuneInstanceStorageEncryptionCheck(Auditor): - def execute(self): - for instances in neptune_instances["DBInstances"]: - neptuneInstanceArn = str(instances["DBInstanceArn"]) - neptuneDbId = str(instances["DBInstanceIdentifier"]) - storageEncryptionCheck = str(instances["StorageEncrypted"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if storageEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn - + "/neptune-instance-storage-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[Neptune.2] Neptune database instace storage should be encrypted", - "Description": "Neptune database instance " - + neptuneDbId - + " does not have storage encryption enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune storage encryption and how to configure it refer to the Enabling Encryption for a Neptune DB Instance section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/encrypt.html#encrypt-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn - + "/neptune-instance-storage-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Neptune.2] Neptune database instace storage should be encrypted", - "Description": "Neptune database instance " - + neptuneDbId - + " has storage encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune storage encryption and how to configure it refer to the Enabling Encryption for a Neptune DB Instance section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/encrypt.html#encrypt-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class NeptuneInstanceIamAuthenticationCheck(Auditor): - def execute(self): - for instances in neptune_instances["DBInstances"]: - neptuneInstanceArn = str(instances["DBInstanceArn"]) - neptuneDbId = str(instances["DBInstanceIdentifier"]) - iamDbAuthCheck = str(instances["IAMDatabaseAuthenticationEnabled"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if iamDbAuthCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn + "/neptune-instance-iam-db-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Neptune.3] Neptune database instaces storage should use IAM Database Authentication", - "Description": "Neptune database instance " - + neptuneDbId - + " does not use IAM Database Authentication. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune IAM Database Authentication and how to configure it refer to the Neptune Database Authentication Using IAM section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": neptuneInstanceArn + "/neptune-instance-iam-db-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": neptuneInstanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Neptune.3] Neptune database instaces storage should use IAM Database Authentication", - "Description": "Neptune database instance " - + neptuneDbId - + " uses IAM Database Authentication.", - "Remediation": { - "Recommendation": { - "Text": "For more information on Neptune IAM Database Authentication and how to configure it refer to the Neptune Database Authentication Using IAM section of the Amazon Neptune User Guide", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": neptuneInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"InstanceId": neptuneDbId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class NeptuneClusterParameterSslEnforcementCheck(Auditor): - def execute(self): - response = neptune.describe_db_cluster_parameter_groups() - for parametergroup in response["DBClusterParameterGroups"]: - parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) - parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) - response = neptune.describe_db_cluster_parameters( - DBClusterParameterGroupName=parameterGroupName - ) - for parameters in response["Parameters"]: - if str(parameters["ParameterName"]) == "neptune_enforce_ssl": - sslEnforcementCheck = str(parameters["ParameterValue"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if sslEnforcementCheck == "0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/neptune-cluster-param-group-ssl-enforcement-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Neptune.4] Neptune cluster parameter groups should enforce SSL connections to Neptune databases", - "Description": "Neptune cluster parameter group " - + parameterGroupName - + " does not enforce SSL connections. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on enforcing SSL/HTTPS connections to Neptune instances refer to the Encryption in Transit: Connecting to Neptune Using SSL/HTTPS section of the Amazon Neptune User Guide.", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/security-ssl.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/neptune-cluster-param-group-ssl-enforcement-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Neptune.4] Neptune cluster parameter groups should enforce SSL connections to Neptune databases", - "Description": "Neptune cluster parameter group " - + parameterGroupName - + " enforces SSL connections.", - "Remediation": { - "Recommendation": { - "Text": "For more information on enforcing SSL/HTTPS connections to Neptune instances refer to the Encryption in Transit: Connecting to Neptune Using SSL/HTTPS section of the Amazon Neptune User Guide.", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/security-ssl.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-2", - "NIST SP 800-53 SC-8", - "NIST SP 800-53 SC-11", - "NIST SP 800-53 SC-12", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.13.2.3", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class NeptuneClusterParameterAuditLogCheck(Auditor): - def execute(self): - response = neptune.describe_db_cluster_parameter_groups() - for parametergroup in response["DBClusterParameterGroups"]: - parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) - parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) - response = neptune.describe_db_cluster_parameters( - DBClusterParameterGroupName=parameterGroupName - ) - for parameters in response["Parameters"]: - if str(parameters["ParameterName"]) == "neptune_enable_audit_log": - auditLogCheck = str(parameters["ParameterValue"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if auditLogCheck == "0": - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/neptune-cluster-param-group-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[Neptune.5] Neptune cluster parameter groups should enforce audit logging for Neptune databases", - "Description": "Neptune cluster parameter group " - + parameterGroupName - + " does not enforce audit logging. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on audit logging for Neptune instances refer to the Enabling Neptune Audit Logs section of the Amazon Neptune User Guide.", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/auditing.html#auditing-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": parameterGroupArn - + "/neptune-cluster-param-group-audit-logging-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": parameterGroupArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[Neptune.5] Neptune cluster parameter groups should enforce audit logging for Neptune databases", - "Description": "Neptune cluster parameter group " - + parameterGroupName - + " enforces audit logging.", - "Remediation": { - "Recommendation": { - "Text": "For more information on audit logging for Neptune instances refer to the Enabling Neptune Audit Logs section of the Amazon Neptune User Guide.", - "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/auditing.html#auditing-enable", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": parameterGroupArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ParameterGroupName": parameterGroupName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass diff --git a/auditors/Amazon_RDS_Auditor.py b/auditors/Amazon_RDS_Auditor.py deleted file mode 100644 index c4a76f6e..00000000 --- a/auditors/Amazon_RDS_Auditor.py +++ /dev/null @@ -1,1619 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -rds = boto3.client("rds") -securityhub = boto3.client("securityhub") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through all RDS DB instances -response = rds.describe_db_instances( - Filters=[ - { - "Name": "engine", - "Values": [ - "aurora", - "aurora-mysql", - "aurora-postgresql", - "mariadb", - "mysql", - "oracle-ee", - "postgres", - "sqlserver-ee", - "sqlserver-se", - "sqlserver-ex", - "sqlserver-web", - ], - } - ], - MaxRecords=100, -) -myRdsInstances = response["DBInstances"] -# loop through all RDS DB snapshots -response = rds.describe_db_snapshots() -myRdsSnapshots = response["DBSnapshots"] - - -class RdsInstanceHaCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - highAvailabilityCheck = str(dbinstances["MultiAZ"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if highAvailabilityCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-ha-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[RDS.1] RDS instances should be configured for high availability", - "Description": "RDS DB instance " - + instanceId - + " is not configured for high availability. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instance high availability and how to configure it refer to the High Availability (Multi-AZ) for Amazon RDS section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-ha-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[RDS.1] RDS instances should be configured for high availability", - "Description": "RDS DB instance " - + instanceId - + " is configured for high availability.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instance high availability and how to configure it refer to the High Availability (Multi-AZ) for Amazon RDS section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsInstancePublicAccessCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - publicAccessibleCheck = str(dbinstances["PubliclyAccessible"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if publicAccessibleCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-public-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[RDS.2] RDS instances should not be publicly accessible", - "Description": "RDS DB instance " - + instanceId - + " is publicly accessible. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instance publicly access and how to change it refer to the Hiding a DB Instance in a VPC from the Internet section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "PubliclyAccessible": True, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-public-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.2] RDS instances should not be publicly accessible", - "Description": "RDS DB instance " - + instanceId - + " is not publicly accessible. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instance publicly access and how to change it refer to the Hiding a DB Instance in a VPC from the Internet section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "PubliclyAccessible": False, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsInstanceStorageEncryptionCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - rdsStorageEncryptionCheck = str(dbinstances["StorageEncrypted"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if rdsStorageEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-storage-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[RDS.3] RDS instances should have encrypted storage", - "Description": "RDS DB instance " - + instanceId - + " does not have encrypted storage. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS storage encryption refer to the Enabling Amazon RDS Encryption for a DB Instance section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html#Overview.Encryption.Enabling", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "StorageEncrypted": False, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-storage-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.3] RDS instances should have encrypted storage", - "Description": "RDS DB instance " - + instanceId - + " has encrypted storage.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS storage encryption refer to the Enabling Amazon RDS Encryption for a DB Instance section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html#Overview.Encryption.Enabling", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "StorageEncrypted": True, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsInstanceIamAuthCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - iamDbAuthCheck = str(dbinstances["IAMDatabaseAuthenticationEnabled"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if instanceEngine == "mysql" or "postgres": - if iamDbAuthCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-iam-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[RDS.4] RDS instances that support IAM Authentication should use IAM Authentication", - "Description": "RDS DB instance " - + instanceId - + " does not support IAM Authentication. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS IAM Database Authentication and how to configure it refer to the IAM Database Authentication for MySQL and PostgreSQL section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "IAMDatabaseAuthenticationEnabled": False, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-iam-auth-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.4] RDS instances that support IAM Authentication should use IAM Authentication", - "Description": "RDS DB instance " - + instanceId - + " supports IAM Authentication.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS IAM Database Authentication and how to configure it refer to the IAM Database Authentication for MySQL and PostgreSQL section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - "IAMDatabaseAuthenticationEnabled": True, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class RdsInstanceDomainJoinCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - activeDirectoryDomainCheck = str(dbinstances["DomainMemberships"]) - if ( - instanceEngine == "mysql" - or "oracle-ee" - or "oracle-se1" - or "oracle-se2" - or "oracle-se" - or "postgres" - or "sqlserver-ee" - or "sqlserver-se" - or "sqlserver-ex" - or "sqlserver-web" - ): - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if activeDirectoryDomainCheck == "[]": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-domain-join-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[RDS.5] RDS instances that support Kerberos Authentication should be joined to a domain", - "Description": "RDS DB instance " - + instanceId - + " is not joined to a domain, and likely does not support Kerberos Authentication because of it. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instances that support Kerberos Authentication and how to configure it refer to the Kerberos Authentication section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/kerberos-authentication.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-domain-join-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.5] RDS instances that support Kerberos Authentication should be joined to a domain", - "Description": "RDS DB instance " - + instanceId - + " is joined to a domain, and likely supports Kerberos Authentication because of it.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS instances that support Kerberos Authentication and how to configure it refer to the Kerberos Authentication section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/kerberos-authentication.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - pass - - -class RdsInstancePerformanceInsightsCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - perfInsightsCheck = str(dbinstances["PerformanceInsightsEnabled"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if perfInsightsCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-perf-insights-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[RDS.6] RDS instances should have performance insights enabled", - "Description": "RDS DB instance " - + instanceId - + " does not have performance insights enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS performance insights and how to configure it refer to the Using Amazon RDS Performance Insights section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-perf-insights-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.6] RDS instances should have performance insights enabled", - "Description": "RDS DB instance " - + instanceId - + " has performance insights enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS performance insights and how to configure it refer to the Using Amazon RDS Performance Insights section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsInstanceDeletionProtectionCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - deletionProtectionCheck = str(dbinstances["DeletionProtection"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if deletionProtectionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-deletion-prot-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[RDS.7] RDS instances should have deletion protection enabled", - "Description": "RDS DB instance " - + instanceId - + " does not have deletion protection enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS deletion protection and how to configure it refer to the Deletion Protection section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_DeleteInstance.html#USER_DeleteInstance.DeletionProtection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "DeletionProtection": False, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-database-cloudwatch-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.7] RDS instances should have deletion protection enabled", - "Description": "RDS DB instance " - + instanceId - + " has deletion protection enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on RDS deletion protection and how to configure it refer to the Deletion Protection section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_DeleteInstance.html#USER_DeleteInstance.DeletionProtection", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "DeletionProtection": False, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsInstanceCloudwatchLoggingCheck(Auditor): - def execute(self): - for dbinstances in myRdsInstances: - instanceArn = str(dbinstances["DBInstanceArn"]) - instanceId = str(dbinstances["DBInstanceIdentifier"]) - instanceClass = str(dbinstances["DBInstanceClass"]) - instancePort = int(dbinstances["Endpoint"]["Port"]) - instanceEngine = str(dbinstances["Engine"]) - instanceEngineVersion = str(dbinstances["EngineVersion"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - logCheck = str(database["EnabledCloudwatchLogsExports"]) - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-database-cloudwatch-logs-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.8] RDS instances should publish database logs to CloudWatch Logs", - "Description": "RDS DB instance " - + instanceId - + " publishes " - + logCheck - + " logs to CloudWatch Logs. Review the types of logs that are published to ensure they fulfill organizational and regulatory requirements as needed.", - "Remediation": { - "Recommendation": { - "Text": "For more information on database logging with CloudWatch and how to configure it refer to the Publishing Database Logs to Amazon CloudWatch Logs section of the Amazon Relational Database Service User Guide. Aurora does support this but you will need to address another User Guide for information on Aurora database logging with CloudWatch", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": instanceArn + "/instance-deletion-prot-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": instanceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[RDS.8] RDS instances should publish database logs to CloudWatch Logs", - "Description": "RDS DB instance " - + instanceId - + " does not publish database logs to CloudWatch Logs. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on database logging with CloudWatch and how to configure it refer to the Publishing Database Logs to Amazon CloudWatch Logs section of the Amazon Relational Database Service User Guide. Aurora does support this but you will need to address another User Guide for information on Aurora database logging with CloudWatch", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": instanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": instanceId, - "DBInstanceClass": instanceClass, - "DbInstancePort": instancePort, - "Engine": instanceEngine, - "EngineVersion": instanceEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF DE.AE-3", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 IR-5", - "NIST SP 800-53 IR-8", - "NIST SP 800-53 SI-4", - "AICPA TSC CC7.2", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.7", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class RdsSnapshotEncryptionCheck(Auditor): - def execute(self): - for snapshot in myRdsSnapshots: - snapshotId = str(snapshot["DBSnapshotIdentifier"]) - snapshotArn = str(snapshot["DBSnapshotArn"]) - snapshotEncryptionCheck = str(snapshot["Encrypted"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if snapshotEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/rds-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[RDS.9] RDS snapshots should be encrypted", - "Description": "RDS snapshot " - + snapshotId - + " is not encrypted. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on encrypting RDS snapshots refer to the AWS Premium Support Knowledge Center Entry How do I encrypt Amazon RDS snapshots?", - "Url": "https://aws.amazon.com/premiumsupport/knowledge-center/encrypt-rds-snapshots/", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbSnapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"SnapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/rds-snapshot-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.9] RDS snapshots should be encrypted", - "Description": "RDS snapshot " + snapshotId + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "For more information on encrypting RDS snapshots refer to the AWS Premium Support Knowledge Center Entry How do I encrypt Amazon RDS snapshots?", - "Url": "https://aws.amazon.com/premiumsupport/knowledge-center/encrypt-rds-snapshots/", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbSnapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"SnapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class RdsSnapshotPublicShareCheck(Auditor): - def execute(self): - for snapshot in myRdsSnapshots: - snapshotId = str(snapshot["DBSnapshotIdentifier"]) - snapshotArn = str(snapshot["DBSnapshotArn"]) - response = rds.describe_db_snapshot_attributes( - DBSnapshotIdentifier=snapshotId - ) - rdsSnapshotAttrs = response["DBSnapshotAttributesResult"][ - "DBSnapshotAttributes" - ] - for attribute in rdsSnapshotAttrs: - attrName = str(attribute["AttributeName"]) - if attrName == "restore": - attrValue = str(attribute["AttributeValues"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if attrValue == "['all']": - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/rds-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - "Sensitive Data Identifications", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "CRITICAL"}, - "Confidence": 99, - "Title": "[RDS.10] RDS snapshots should not be publicly shared", - "Description": "RDS snapshot " - + snapshotId - + " is publicly shared. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on sharing RDS snapshots refer to the Sharing a Snapshot section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ShareSnapshot.html#USER_ShareSnapshot.Sharing", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbSnapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"SnapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": snapshotArn + "/rds-snapshot-public-share-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": snapshotArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - "Sensitive Data Identifications", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[RDS.10] RDS snapshots should not be publicly shared", - "Description": "RDS snapshot " - + snapshotId - + " is not publicly shared.", - "Remediation": { - "Recommendation": { - "Text": "For more information on sharing RDS snapshots refer to the Sharing a Snapshot section of the Amazon Relational Database Service User Guide", - "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ShareSnapshot.html#USER_ShareSnapshot.Sharing", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbSnapshot", - "Id": snapshotArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"SnapshotId": snapshotId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - print("non-supported attribute encountered") - pass diff --git a/auditors/Amazon_Redshift_Auditor.py b/auditors/Amazon_Redshift_Auditor.py deleted file mode 100644 index 7affd281..00000000 --- a/auditors/Amazon_Redshift_Auditor.py +++ /dev/null @@ -1,513 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -redshift = boto3.client('redshift') -# create env vars -awsRegion = os.environ['AWS_REGION'] -awsAccountId = sts.get_caller_identity()['Account'] -# loop through redshift clusters -response = redshift.describe_clusters() -myRedshiftClusters = response['Clusters'] - -class ClusterPublicAccessCheck(Auditor): - def execute(self): - for cluster in myRedshiftClusters: - clusterId = str(cluster['ClusterIdentifier']) - clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(cluster['PubliclyAccessible']) == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'CRITICAL' }, - 'Confidence': 99, - 'Title': '[Redshift.1] Redshift clusters should not be publicly accessible', - 'Description': 'Redshift cluster ' + clusterId + ' is publicly accessible. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on modifying Redshift public access refer to the Modifying a Cluster section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html#modify-cluster' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Redshift.1] Redshift clusters should not be publicly accessible', - 'Description': 'Redshift cluster ' + clusterId + ' is not publicly accessible.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on modifying Redshift public access refer to the Modifying a Cluster section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html#modify-cluster' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class ClusterEncryptionCheck(Auditor): - def execute(self): - for cluster in myRedshiftClusters: - clusterId = str(cluster['ClusterIdentifier']) - clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(cluster['Encrypted']) == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-cluster-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[Redshift.2] Redshift clusters should be encrypted', - 'Description': 'Redshift cluster ' + clusterId + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift cluster encryption and how to configure it refer to the Amazon Redshift Database Encryption section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-db-encryption.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-cluster-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Redshift.2] Redshift clusters should be encrypted', - 'Description': 'Redshift cluster ' + clusterId + ' is encrypted.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift cluster encryption and how to configure it refer to the Amazon Redshift Database Encryption section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-db-encryption.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class ClusterEnhancedVPCRoutingCheck(Auditor): - def execute(self): - for cluster in myRedshiftClusters: - clusterId = str(cluster['ClusterIdentifier']) - clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(cluster['EnhancedVpcRouting']) == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-cluster-enhanced-vpc-routing-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Redshift.3] Redshift clusters should utilize enhanced VPC routing', - 'Description': 'Redshift cluster ' + clusterId + ' is not utilizing enhanced VPC routing. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift Enhanced VPC routing and how to configure it refer to the Amazon Redshift Enhanced VPC Routing section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/enhanced-vpc-routing.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-enhanced-vpc-routing-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Redshift.3] Redshift clusters should utilize enhanced VPC routing', - 'Description': 'Redshift cluster ' + clusterId + ' is utilizing enhanced VPC routing.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift Enhanced VPC routing and how to configure it refer to the Amazon Redshift Enhanced VPC Routing section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/enhanced-vpc-routing.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class ClusterLoggingCheck(Auditor): - def execute(self): - for cluster in myRedshiftClusters: - clusterId = str(cluster['ClusterIdentifier']) - clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId - response = redshift.describe_logging_status(ClusterIdentifier=clusterId) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(response['LoggingEnabled']) == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-cluster-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[Redshift.4] Redshift clusters should have logging enabled', - 'Description': 'Redshift cluster ' + clusterId + ' does not have logging enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift logging and how to configure it refer to the Database Audit Logging section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': clusterArn + '/redshift-cluster-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': clusterArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[Redshift.4] Redshift clusters should have logging enabled', - 'Description': 'Redshift cluster ' + clusterId + ' has logging enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Redshift logging and how to configure it refer to the Database Audit Logging section of the Amazon Redshift Cluster Management Guide', - 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsRedshiftCluster', - 'Id': clusterArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'ClusterId': clusterId - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/Amazon_S3_Auditor.py b/auditors/Amazon_S3_Auditor.py deleted file mode 100644 index 43e8b9b3..00000000 --- a/auditors/Amazon_S3_Auditor.py +++ /dev/null @@ -1,865 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -s3 = boto3.client('s3') -s3control = boto3.client('s3control') -# create env vars -awsRegion = os.environ['AWS_REGION'] -awsAccountId = sts.get_caller_identity()['Account'] -# loop through s3 buckets -response = s3.list_buckets() -myS3Buckets = response['Buckets'] - -class BucketEncryptionCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - try: - response = s3.get_bucket_encryption(Bucket=bucketName) - for rules in response['ServerSideEncryptionConfiguration']['Rules']: - sseType = str(rules['ApplyServerSideEncryptionByDefault']['SSEAlgorithm']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.1] S3 Buckets should be encrypted', - 'Description': 'S3 bucket ' + bucketName + ' is encrypted using ' + sseType + '.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Encryption and how to configure it refer to the Amazon S3 Default Encryption for S3 Buckets section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == 'An error occurred (ServerSideEncryptionConfigurationNotFoundError) when calling the GetBucketEncryption operation: The server side encryption configuration was not found': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[S3.1] S3 Buckets should be encrypted', - 'Description': 'S3 bucket ' + bucketName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Encryption and how to configure it refer to the Amazon S3 Default Encryption for S3 Buckets section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class BucketLifecycleCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = s3.get_bucket_lifecycle_configuration(Bucket=bucketName) - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-lifecyle-configuration-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.2] S3 Buckets should implement lifecycle policies for data archival and recovery operations', - 'Description': 'S3 bucket ' + bucketName + ' has a lifecycle policy configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Lifecycle policies and how to configure it refer to the How Do I Create a Lifecycle Policy for an S3 Bucket? section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == 'An error occurred (NoSuchLifecycleConfiguration) when calling the GetBucketLifecycleConfiguration operation: The lifecycle configuration does not exist': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-lifecyle-configuration-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[S3.2] S3 Buckets should implement lifecycle policies for data archival and recovery operations', - 'Description': 'S3 bucket ' + bucketName + ' does not have a lifecycle policy configured. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Lifecycle policies and how to configure it refer to the How Do I Create a Lifecycle Policy for an S3 Bucket? section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class BucketVersioningCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = s3.get_bucket_versioning(Bucket=bucketName) - versioningCheck = str(response['Status']) - print(versioningCheck) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-versioning-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.3] S3 Buckets should have versioning enabled', - 'Description': 'S3 bucket ' + bucketName + ' has versioning enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Versioning and how to configure it refer to the Using Versioning section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'Status'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-versioning-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'LOW' }, - 'Confidence': 99, - 'Title': '[S3.3] S3 Buckets should have versioning enabled', - 'Description': 'S3 bucket ' + bucketName + ' does not have versioning enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Versioning and how to configure it refer to the Using Versioning section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF ID.BE-5', - 'NIST CSF PR.PT-5', - 'NIST SP 800-53 CP-2', - 'NIST SP 800-53 CP-11', - 'NIST SP 800-53 SA-13', - 'NIST SP 800-53 SA14', - 'AICPA TSC CC3.1', - 'AICPA TSC A1.2', - 'ISO 27001:2013 A.11.1.4', - 'ISO 27001:2013 A.17.1.1', - 'ISO 27001:2013 A.17.1.2', - 'ISO 27001:2013 A.17.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class BucketPolicyAllowsPublicAccessCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = s3.get_bucket_policy(Bucket=bucketName) - try: - response = s3.get_bucket_policy_status(Bucket=bucketName) - publicBucketPolicyCheck = str(response['PolicyStatus']['IsPublic']) - if publicBucketPolicyCheck != 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-policy-allows-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'CRITICAL' }, - 'Confidence': 99, - 'Title': '[S3.4] S3 Bucket Policies should not allow public access to the bucket', - 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy attached that allows public access. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-policy-allows-public-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.4] S3 Bucket Policies should not allow public access to the bucket', - 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy attached and it does not allow public access.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - print(e) - except Exception as e: - print('This bucket does not have a bucket policy and the status cannot be checked') - pass - -class BucketPolicyCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = s3.get_bucket_policy(Bucket=bucketName) - print('This bucket has a policy but we wont be printing that in the logs lol') - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-policy-exists-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.5] S3 Buckets should have a bucket policy configured', - 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == 'An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-policy-exists-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[S3.5] S3 Buckets should have a bucket policy configured', - 'Description': 'S3 bucket ' + bucketName + ' does not have a bucket policy configured. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class BucketAccessLoggingCheck(Auditor): - def execute(self): - for buckets in myS3Buckets: - bucketName = str(buckets['Name']) - s3Arn = 'arn:aws:s3:::' + bucketName - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - response = s3.get_bucket_logging(Bucket=bucketName) - accessLoggingCheck = str(response['LoggingEnabled']) - # this is a passing check - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-server-access-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.6] S3 Buckets should have server access logging enabled', - 'Description': 'S3 bucket ' + bucketName + ' does not have server access logging enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Amazon S3 Server Access Logging section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except Exception as e: - if str(e) == "'LoggingEnabled'": - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': s3Arn + '/s3-bucket-server-access-logging-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': s3Arn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[S3.6] S3 Buckets should have server access logging enabled', - 'Description': 'S3 bucket ' + bucketName + ' does not have server access logging enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Bucket Policies and how to configure it refer to the Amazon S3 Server Access Logging section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsS3Bucket', - 'Id': s3Arn, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - print(e) - -class S3AccountLevelBlock(Auditor): - def execute(self): - response = s3control.get_public_access_block(AccountId=awsAccountId) - accountBlock = response['PublicAccessBlockConfiguration'] - blockAcl = str(accountBlock['BlockPublicAcls']) - ignoreAcl = str(accountBlock['IgnorePublicAcls']) - blockPubPolicy = str(accountBlock['BlockPublicPolicy']) - restrictPubBuckets = str(accountBlock['RestrictPublicBuckets']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if blockAcl and ignoreAcl and blockPubPolicy and restrictPubBuckets == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/s3-account-level-public-access-block-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': awsAccountId, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[S3.7] Account-level S3 public access block should be configured', - 'Description': 'Account-level S3 public access block for account ' + awsAccountId + ' is enabled', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Account level S3 public access block and how to configure it refer to the Using Amazon S3 Block Public Access section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': awsAccountId + '/s3-account-level-public-access-block-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': awsAccountId, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[S3.7] Account-level S3 public access block should be configured', - 'Description': 'Account-level S3 public access block for account ' + awsAccountId + ' is either inactive or is not block all possible scenarios. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on Account level S3 public access block and how to configure it refer to the Using Amazon S3 Block Public Access section of the Amazon Simple Storage Service Developer Guide', - 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'AwsAccount', - 'Id': 'AWS::::Account:' + awsAccountId, - 'Partition': 'aws', - 'Region': awsRegion - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-3', - 'NIST SP 800-53 AC-1', - 'NIST SP 800-53 AC-17', - 'NIST SP 800-53 AC-19', - 'NIST SP 800-53 AC-20', - 'NIST SP 800-53 SC-15', - 'AICPA TSC CC6.6', - 'ISO 27001:2013 A.6.2.1', - 'ISO 27001:2013 A.6.2.2', - 'ISO 27001:2013 A.11.2.6', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.2.1' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding diff --git a/auditors/Amazon_SNS_Auditor.py b/auditors/Amazon_SNS_Auditor.py deleted file mode 100644 index 6720a5d1..00000000 --- a/auditors/Amazon_SNS_Auditor.py +++ /dev/null @@ -1,611 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import datetime -import json -import os -import boto3 -from auditors.Auditor import Auditor - -# import boto3 clients -sns = boto3.client("sns") -sts = boto3.client("sts") -# create region variable -awsRegion = os.environ["AWS_REGION"] - - -class SNSTopicEncryptionCheck(Auditor): - def execute(self): - awsAccountId = sts.get_caller_identity()["Account"] - # loop through SNS topics - response = sns.list_topics() - mySnsTopics = response["Topics"] - for topic in mySnsTopics: - topicarn = str(topic["TopicArn"]) - topicName = topicarn.replace( - "arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "" - ) - response = sns.get_topic_attributes(TopicArn=topicarn) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - encryptionCheck = str(response["Attributes"]["KmsMasterKeyId"]) - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-topic-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SNS.1] SNS topics should be encrypted", - "Description": "SNS topic " + topicName + " is encrypted.", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-topic-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[SNS.1] SNS topics should be encrypted", - "Description": "SNS topic " - + topicName - + " is not encrypted. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class SNSHTTPEncryptionCheck(Auditor): - def execute(self): - awsAccountId = sts.get_caller_identity()["Account"] - # loop through SNS topics - response = sns.list_topics() - mySnsTopics = response["Topics"] - for topic in mySnsTopics: - topicarn = str(topic["TopicArn"]) - topicName = topicarn.replace( - "arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "" - ) - response = sns.list_subscriptions_by_topic(TopicArn=topicarn) - mySubs = response["Subscriptions"] - for subscriptions in mySubs: - subProtocol = str(subscriptions["Protocol"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if subProtocol == "http": - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-http-subscription-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[SNS.2] SNS topics should not use HTTP subscriptions", - "Description": "SNS topic " - + topicName - + " has a HTTP subscriber. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-http-subscription-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SNS.2] SNS topics should not use HTTP subscriptions", - "Description": "SNS topic " - + topicName - + " does not have a HTTP subscriber.", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class SNSPublicAccessCheck(Auditor): - def execute(self): - awsAccountId = sts.get_caller_identity()["Account"] - # loop through SNS topics - response = sns.list_topics() - mySnsTopics = response["Topics"] - for topic in mySnsTopics: - topicarn = str(topic["TopicArn"]) - topicName = topicarn.replace( - "arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "" - ) - response = sns.get_topic_attributes(TopicArn=topicarn) - statement_json = response["Attributes"]["Policy"] - statement = json.loads(statement_json) - fail = False - # this results in one finding per topic instead of one finding per statement - for sid in statement["Statement"]: - access = sid["Principal"]["AWS"] - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if access != "*" or (access == "*" and "Condition" in sid): - continue - else: - fail = True - break - if not fail: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-public-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 75, # The Condition may not effectively limit access - "Title": "[SNS.3] SNS topics should not have public access", - "Description": "SNS topic " - + topicName - + " does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-public-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[SNS.3] SNS topics should not have public access", - "Description": "SNS topic " - + topicName - + " has public access. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"AwsSnsTopic": {"TopicName": topicName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - -class SNSCrossAccountCheck(Auditor): - def execute(self): - awsAccountId = sts.get_caller_identity()["Account"] - # loop through SNS topics - response = sns.list_topics() - mySnsTopics = response["Topics"] - for topic in mySnsTopics: - topicarn = str(topic["TopicArn"]) - topicName = topicarn.replace( - "arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "" - ) - response = sns.get_topic_attributes(TopicArn=topicarn) - myPolicy_json = str(response["Attributes"]["Policy"]) - myPolicy = json.loads(myPolicy_json) - for statement in myPolicy["Statement"]: - principal = statement["Principal"]["AWS"] - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if principal[0] != "*": - if not principal[0].isdigit(): - principal = principal.split(":")[4] - if principal == awsAccountId: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-cross-account-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[SNS.4] SNS topics should not allow cross-account access", - "Description": "SNS topic " - + topicName - + " does not have cross-account access.", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS best practices refer to the Amazon SNS security best practices section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsSnsTopic": {"TopicName": topicName} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": topicarn + "/sns-cross-account-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": topicarn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "Low"}, - "Confidence": 99, - "Title": "[SNS.4] SNS topics should not allow cross-account access", - "Description": "SNS topic " - + topicName - + " has cross-account access.", - "Remediation": { - "Recommendation": { - "Text": "For more information on SNS best practices refer to the Amazon SNS security best practices section of the Amazon Simple Notification Service Developer Guide.", - "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsSnsTopic", - "Id": topicarn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsSnsTopic": {"TopicName": topicName} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-3", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-17", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-20", - "NIST SP 800-53 SC-15", - "AICPA TSC CC6.6", - "ISO 27001:2013 A.6.2.1", - "ISO 27001:2013 A.6.2.2", - "ISO 27001:2013 A.11.2.6", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding diff --git a/auditors/Amazon_SageMaker_Auditor.py b/auditors/Amazon_SageMaker_Auditor.py deleted file mode 100644 index f00b2ebc..00000000 --- a/auditors/Amazon_SageMaker_Auditor.py +++ /dev/null @@ -1,662 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor -# import boto3 clients -sts = boto3.client('sts') -sagemaker = boto3.client('sagemaker') -# create env vars -awsRegion = os.environ['AWS_REGION'] -awsAccountId = sts.get_caller_identity()['Account'] - -class SagemakerNotebookEncryptionCheck(Auditor): - def execute(self): - # loop through sagemaker notebooks - response = sagemaker.list_notebook_instances() - mySageMakerNotebooks = response['NotebookInstances'] - for notebooks in mySageMakerNotebooks: - notebookName = str(notebooks['NotebookInstanceName']) - response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) - notebookArn = str(response['NotebookInstanceArn']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - notebookEncryptionCheck = str(response['KmsKeyId']) - print(notebookEncryptionCheck) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SageMaker.1] SageMaker notebook instance storage volumes should be encrypted', - 'Description': 'SageMaker notebook instance ' + notebookName + ' is encrypted.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[SageMaker.1] SageMaker notebook instance storage volumes should be encrypted', - 'Description': 'SageMaker notebook instance ' + notebookName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class SagemakerNotebookDirectInternetAccessCheck(Auditor): - def execute(self): - # loop through sagemaker notebooks - response = sagemaker.list_notebook_instances() - mySageMakerNotebooks = response['NotebookInstances'] - for notebooks in mySageMakerNotebooks: - notebookName = str(notebooks['NotebookInstanceName']) - response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) - notebookArn = str(response['NotebookInstanceArn']) - directInternetCheck = str(response['DirectInternetAccess']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if directInternetCheck == 'Enabled': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-direct-internet-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[SageMaker.2] SageMaker notebook instances should not have direct internet access configured', - 'Description': 'SageMaker notebook instance ' + notebookName + ' has direct internet access configured. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-direct-internet-access-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SageMaker.2] SageMaker notebook instances should not have direct internet access configured', - 'Description': 'SageMaker notebook instance ' + notebookName + ' does not have direct internet access configured.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class SagemakerNotebookInVPCCheck(Auditor): - def execute(self): - # loop through sagemaker notebooks - response = sagemaker.list_notebook_instances() - mySageMakerNotebooks = response['NotebookInstances'] - for notebooks in mySageMakerNotebooks: - notebookName = str(notebooks['NotebookInstanceName']) - response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) - notebookArn = str(response['NotebookInstanceArn']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - inVpcCheck = str(response['SubnetId']) - print(inVpcCheck) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-in-vpc-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SageMaker.3] SageMaker notebook instances should be placed in a VPC', - 'Description': 'SageMaker notebook instance ' + notebookName + ' is not in a VPC. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': notebookArn + '/sagemaker-notebook-in-vpc-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': notebookArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SageMaker.3] SageMaker notebook instances should be placed in a VPC', - 'Description': 'SageMaker notebook instance ' + notebookName + ' is in a VPC.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': notebookArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'notebookName': notebookName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class SagemakerEndpointEncryptionCheck(Auditor): - def execute(self): - # loop through sagemaker endpoints - response = sagemaker.list_endpoints() - mySageMakerEndpoints = response['Endpoints'] - for endpoints in mySageMakerEndpoints: - endpointName = str(endpoints['EndpointName']) - response = sagemaker.describe_endpoint(EndpointName=endpointName) - endpointArn = str(response['EndpointArn']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - try: - dataCaptureEncryptionCheck = str(response['DataCaptureConfig']['KmsKeyId']) - print(dataCaptureEncryptionCheck) - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': endpointArn + '/sagemaker-endpoint-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': endpointArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SageMaker.4] SageMaker endpoints should be encrypted', - 'Description': 'SageMaker endpoint ' + endpointName + ' is encrypted.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': endpointArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'endpointName': endpointName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - except: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': endpointArn + '/sagemaker-endpoint-encryption-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': endpointArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'HIGH' }, - 'Confidence': 99, - 'Title': '[SageMaker.4] SageMaker endpoints should be encrypted', - 'Description': 'SageMaker endpoint ' + endpointName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': endpointArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'endpointName': endpointName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.DS-1', - 'NIST SP 800-53 MP-8', - 'NIST SP 800-53 SC-12', - 'NIST SP 800-53 SC-28', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.8.2.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - -class SagemakerModelNetworkIsolationCheck(Auditor): - def execute(self): - # loop through sagemaker models - response = sagemaker.list_models() - mySageMakerModels = response['Models'] - for models in mySageMakerModels: - modelName = str(models['ModelName']) - modelArn = str(models['ModelArn']) - response = sagemaker.describe_model(ModelName=modelName) - networkIsolationCheck = str(response['EnableNetworkIsolation']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if networkIsolationCheck == 'False': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': modelArn + '/sagemaker-model-network-isolation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': modelArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[SageMaker.5] SageMaker models should have network isolation enabled', - 'Description': 'SageMaker model ' + modelName + ' does not have network isolation enabled. Refer to the remediation instructions to remediate this behavior', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker model network isolation and how to configure it refer to the Training and Inference Containers Run in Internet-Free Mode section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/mkt-algo-model-internet-free.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': modelArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'modelName': modelName - } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': modelArn + '/sagemaker-model-network-isolation-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': modelArn, - 'AwsAccountId': awsAccountId, - 'Types': [ - 'Software and Configuration Checks/AWS Security Best Practices', - 'Effects/Data Exposure' - ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[SageMaker.5] SageMaker models should have network isolation enabled', - 'Description': 'SageMaker model ' + modelName + ' has network isolation enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on SageMaker model network isolation and how to configure it refer to the Training and Inference Containers Run in Internet-Free Mode section of the Amazon SageMaker Developer Guide', - 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/mkt-algo-model-internet-free.html' - } - }, - 'ProductFields': { 'Product Name': 'ElectricEye' }, - 'Resources': [ - { - 'Type': 'Other', - 'Id': modelArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { - 'modelName': modelName - } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/Amazon_Shield_Advanced_Auditor.py b/auditors/Amazon_Shield_Advanced_Auditor.py deleted file mode 100644 index a5789bce..00000000 --- a/auditors/Amazon_Shield_Advanced_Auditor.py +++ /dev/null @@ -1,1222 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -shield = boto3.client("shield") -route53 = boto3.client("route53") -elbclassic = boto3.client("elb") -elbv2 = boto3.client("elbv2") -ec2 = boto3.client("ec2") -cloudfront = boto3.client("cloudfront") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -if awsRegion != "us-east-1": - print("Shield Advanced APIs are only available in North Virginia") -else: - - class ShieldAdvancedRoute53ProtectionCheck(Auditor): - def execute(self): - response = route53.list_hosted_zones() - for hostedzone in response["HostedZones"]: - rawHzId = str(hostedzone["Id"]) - hostedZoneId = rawHzId.replace("/hostedzone/", "") - hostedZoneArn = "arn:aws:route53:::hostedzone/" + hostedZoneId - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - response = shield.describe_protection(ResourceArn=hostedZoneArn) - finding = { - "SchemaVersion": "2018-10-08", - "Id": hostedZoneArn + "/route53-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": hostedZoneArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.1] Route 53 Hosted Zones should be protected by Shield Advanced", - "Description": "Route53 Hosted Zone " - + hostedZoneId - + " is protected by Shield Advanced.", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRoute53HostedZone", - "Id": hostedZoneArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"hostedZoneId": hostedZoneId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if ( - str(e) - == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": hostedZoneArn - + "/route53-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": hostedZoneArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.1] Route 53 Hosted Zones should be protected by Shield Advanced", - "Description": "Route53 Hosted Zone " - + hostedZoneId - + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRoute53HostedZone", - "Id": hostedZoneArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"hostedZoneId": hostedZoneId} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - class ShieldAdvancedELBProtectionCheck(Auditor): - def execute(self): - response = elbclassic.describe_load_balancers() - for classicbalancer in response["LoadBalancerDescriptions"]: - clbName = str(classicbalancer["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - response = shield.describe_protection(ResourceArn=clbArn) - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classiclb-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.2] Classic Load Balancers should be protected by Shield Advanced", - "Description": "Classic Load Balancer " - + clbName - + " is protected by Shield Advanced.", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if ( - str(e) - == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn + "/classiclb-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.2] Classic Load Balancers should be protected by Shield Advanced", - "Description": "Classic Load Balancer " - + clbName - + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - class ShieldAdvancedELBV2ProtectionCheck(Auditor): - def execute(self): - response = elbv2.describe_load_balancers() - for loadbalancer in response["LoadBalancers"]: - elbv2Name = str(loadbalancer["LoadBalancerName"]) - elbv2Arn = str(loadbalancer["LoadBalancerArn"]) - elbv2DnsName = str(loadbalancer["DNSName"]) - elbv2LbType = str(loadbalancer["Type"]) - elbv2Scheme = str(loadbalancer["Scheme"]) - elbv2VpcId = str(loadbalancer["VpcId"]) - elbv2IpAddressType = str(loadbalancer["IpAddressType"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - response = shield.describe_protection(ResourceArn=elbv2Arn) - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.3] ELBv2 Load Balancers should be protected by Shield Advanced", - "Description": "ELBv2 " - + elbv2LbType - + " load balancer " - + elbv2Name - + " is protected by Shield Advanced.", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if ( - str(e) - == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/elbv2-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.3] ELBv2 Load Balancers should be protected by Shield Advanced", - "Description": "ELBv2 " - + elbv2LbType - + " load balancer " - + elbv2Name - + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2DnsName, - "IpAddressType": elbv2IpAddressType, - "Scheme": elbv2Scheme, - "Type": elbv2LbType, - "VpcId": elbv2VpcId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - class ShieldAdvancedEIPProtectionCheck(Auditor): - def execute(self): - response = ec2.describe_addresses() - for elasticip in response["Addresses"]: - # arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:eip/${EIP1.AllocationId} - allocationId = str(elasticip["AllocationId"]) - eipAllocationArn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + ":eip-allocation/" - + allocationId - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - response = shield.describe_protection(ResourceArn=eipAllocationArn) - finding = { - "SchemaVersion": "2018-10-08", - "Id": eipAllocationArn - + "/elasticip-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": eipAllocationArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.4] Elastic IPs should be protected by Shield Advanced", - "Description": "Elastic IP allocation " - + allocationId - + " is protected by Shield Advanced.", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Eip", - "Id": eipAllocationArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"AllocationId": allocationId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if ( - str(e) - == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": eipAllocationArn - + "/elasticip-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": eipAllocationArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.4] Elastic IPs should be protected by Shield Advanced", - "Description": "Elastic IP allocation " - + allocationId - + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Eip", - "Id": eipAllocationArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"AllocationId": allocationId} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - class ShieldAdvancedCloudfrontProtectionCheck(Auditor): - def execute(self): - response = cloudfront.list_distributions() - cfDistros = response["DistributionList"]["Items"] - for distro in cfDistros: - distroId = str(distro["Id"]) - distroArn = str(distro["ARN"]) - distroDomainName = str(distro["DomainName"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - response = shield.describe_protection(ResourceArn=distroArn) - finding = { - "SchemaVersion": "2018-10-08", - "Id": distroArn + "/cloudfront-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": distroArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.5] CloudFront distributions should be protected by Shield Advanced", - "Description": "CloudFront distribution " - + distroId - + " is protected by Shield Advanced.", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCloudFrontDistribution", - "Id": distroArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCloudFrontDistribution": { - "DomainName": distroDomainName - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - if ( - str(e) - == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." - ): - finding = { - "SchemaVersion": "2018-10-08", - "Id": distroArn + "/cloudfront-shield-adv-protection-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": distroArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.5] CloudFront distributions should be protected by Shield Advanced", - "Description": "CloudFront distribution " - + distroId - + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", - "Remediation": { - "Recommendation": { - "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsCloudFrontDistribution", - "Id": distroArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsCloudFrontDistribution": { - "DomainName": distroDomainName - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.BE-5", - "NIST CSF PR.PT-5", - "NIST SP 800-53 CP-2", - "NIST SP 800-53 CP-11", - "NIST SP 800-53 SA-13", - "NIST SP 800-53 SA14", - "AICPA TSC CC3.1", - "AICPA TSC A1.2", - "ISO 27001:2013 A.11.1.4", - "ISO 27001:2013 A.17.1.1", - "ISO 27001:2013 A.17.1.2", - "ISO 27001:2013 A.17.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - - class ShieldAdvancedDRTAccessCheck(Auditor): - def execute(self): - response = shield.describe_drt_access() - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - # this is a passing check - drtRole = str(response["RoleArn"]) - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-drt-iam-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.6] The DDoS Response Team (DRT) should be authorized to take action in your account", - "Description": "The Shield Advanced DRT is authorized to take action in Account " - + awsAccountId - + " with the IAM role " - + drtRole, - "Remediation": { - "Recommendation": { - "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-drt-iam-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.6] The DDoS Response Team (DRT) should be authorized to take action in your account", - "Description": "The Shield Advanced DRT is not authorized to take action in Account " - + awsAccountId - + " . Refer to the remediation instructions if this configuration is not intended.", - "Remediation": { - "Recommendation": { - "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - class ShieldAdvancedDRTs3bucketCheck(Auditor): - def execute(self): - response = shield.describe_drt_access() - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - logBucketList = str(response["LogBucketList"]) - print(logBucketList) - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-drt-s3bucket-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.7] The DDoS Response Team (DRT) should be authorized to view your AWS Web Application Firewall (WAF) logging buckets", - "Description": "The Shield Advanced DRT is authorized to view one or more WAF log S3 buckets in " - + awsAccountId, - "Remediation": { - "Recommendation": { - "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except: - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-drt-s3bucket-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.7] The DDoS Response Team (DRT) should be authorized to view your AWS Web Application Firewall (WAF) logging buckets", - "Description": "The Shield Advanced DRT is not authorized to view any WAF log S3 buckets in " - + awsAccountId - + " . Refer to the remediation instructions if this configuration is not intended.", - "Remediation": { - "Recommendation": { - "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", - "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-6", - "NIST SP 800-53 AC-1", - "NIST SP 800-53 AC-2", - "NIST SP 800-53 AC-3", - "NIST SP 800-53 AC-16", - "NIST SP 800-53 AC-19", - "NIST SP 800-53 AC-24", - "NIST SP 800-53 IA-1", - "NIST SP 800-53 IA-2", - "NIST SP 800-53 IA-4", - "NIST SP 800-53 IA-5", - "NIST SP 800-53 IA-8", - "NIST SP 800-53 PE-2", - "NIST SP 800-53 PS-3", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.7.1.1", - "ISO 27001:2013 A.9.2.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - - class ShieldAdvancedSubscriptionAutorenewCheck(Auditor): - def execute(self): - response = shield.describe_subscription() - renewCheck = str(response["Subscription"]["AutoRenew"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if renewCheck != "ENABLED": - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-subscription-auto-renew-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.8] Shield Advanced subscription should be set to auto-renew", - "Description": "The Shield Advanced subscription for " - + awsAccountId - + " is not set to auto-renew. Refer to the remediation instructions if this configuration is not intended.", - "Remediation": { - "Recommendation": { - "Text": "To update the subscription renewel use the UpdateSubscription API, refer to the link for more details.", - "Url": "https://docs.aws.amazon.com/waf/latest/DDOSAPIReference/API_UpdateSubscription.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": awsAccountId + "/shield-adv-subscription-auto-renew-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": awsAccountId, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[ShieldAdvanced.8] Shield Advanced subscription should be set to auto-renew", - "Description": "The Shield Advanced subscription for " - + awsAccountId - + " is set to auto-renew", - "Remediation": { - "Recommendation": { - "Text": "To update the subscription renewel use the UpdateSubscription API, refer to the link for more details.", - "Url": "https://docs.aws.amazon.com/waf/latest/DDOSAPIReference/API_UpdateSubscription.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsAccount", - "Id": "AWS::::Account:" + awsAccountId, - "Partition": "aws", - "Region": awsRegion, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Amazon_VPC_Auditor.py b/auditors/Amazon_VPC_Auditor.py deleted file mode 100644 index cbd09826..00000000 --- a/auditors/Amazon_VPC_Auditor.py +++ /dev/null @@ -1,277 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import datetime -import os -from auditors.Auditor import Auditor -# create boto3 clients -sts = boto3.client('sts') -ec2 = boto3.client('ec2') -# create env vars -awsAccountId = sts.get_caller_identity()['Account'] -#awsRegion = os.environ['AWS_REGION'] -awsRegion = 'us-east-1' -# loop through vpcs -response = ec2.describe_vpcs(DryRun=False) -myVpcs = response['Vpcs'] - -class vpcDefaultCheck(Auditor): - def execute(self): - for vpcs in myVpcs: - vpcId = str(vpcs['VpcId']) - vpcArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + 'vpc/' + vpcId - defaultVpcCheck = str(vpcs['IsDefault']) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if defaultVpcCheck == 'True': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': vpcArn + '/vpc-is-default-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': vpcArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[VPC.1] Consider deleting the Default VPC if unused', - 'Description': 'VPC ' + vpcId + ' has been identified as the Default VPC, consider deleting this VPC if it is not necessary for daily operations. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on the default VPC refer to the Deleting Your Default Subnets and Default VPC section of the Amazon Virtual Private Cloud User Guide', - 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#deleting-default-vpc' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Vpc', - 'Id': vpcArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'vpcId': vpcId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': vpcArn + '/vpc-is-default-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': vpcArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[VPC.1] Consider deleting the Default VPC if unused', - 'Description': 'VPC ' + vpcId + ' is not the Default VPC', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on the default VPC refer to the Deleting Your Default Subnets and Default VPC section of the Amazon Virtual Private Cloud User Guide', - 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#deleting-default-vpc' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Vpc', - 'Id': vpcArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'vpcId': vpcId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF PR.AC-5', - 'NIST SP 800-53 AC-4', - 'NIST SP 800-53 AC-10', - 'NIST SP 800-53 SC-7', - 'AICPA TSC CC6.1', - 'ISO 27001:2013 A.13.1.1', - 'ISO 27001:2013 A.13.1.3', - 'ISO 27001:2013 A.13.2.1', - 'ISO 27001:2013 A.14.1.2', - 'ISO 27001:2013 A.14.1.3' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding - -class vpcFlowLogsCheck(Auditor): - def execute(self): - for vpcs in myVpcs: - vpcId = str(vpcs['VpcId']) - vpcArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + 'vpc/' + vpcId - response = ec2.describe_flow_logs( - DryRun=False, - Filters=[ - { - 'Name': 'resource-id', - 'Values': [ vpcId ] - } - ] - ) - iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() - if str(response['FlowLogs']) == '[]': - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': vpcArn + '/vpc-flow-log-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': vpcArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'MEDIUM' }, - 'Confidence': 99, - 'Title': '[VPC.2] Flow Logs should be enabled for all VPCs', - 'Description': 'VPC ' + vpcId + ' does not have flow logging enabled. Refer to the remediation instructions if this configuration is not intended', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on flow logs refer to the VPC Flow Logs section of the Amazon Virtual Private Cloud User Guide', - 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Vpc', - 'Id': vpcArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'vpcId': vpcId } - } - } - ], - 'Compliance': { - 'Status': 'FAILED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'NEW' - }, - 'RecordState': 'ACTIVE' - } - yield finding - else: - finding = { - 'SchemaVersion': '2018-10-08', - 'Id': vpcArn + '/vpc-flow-log-check', - 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', - 'GeneratorId': vpcArn, - 'AwsAccountId': awsAccountId, - 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], - 'FirstObservedAt': iso8601Time, - 'CreatedAt': iso8601Time, - 'UpdatedAt': iso8601Time, - 'Severity': { 'Label': 'INFORMATIONAL' }, - 'Confidence': 99, - 'Title': '[VPC.2] Flow Logs should be enabled for all VPCs', - 'Description': 'VPC ' + vpcId + ' has flow logging enabled.', - 'Remediation': { - 'Recommendation': { - 'Text': 'For more information on flow logs refer to the VPC Flow Logs section of the Amazon Virtual Private Cloud User Guide', - 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html' - } - }, - 'ProductFields': { - 'Product Name': 'ElectricEye' - }, - 'Resources': [ - { - 'Type': 'AwsEc2Vpc', - 'Id': vpcArn, - 'Partition': 'aws', - 'Region': awsRegion, - 'Details': { - 'Other': { 'vpcId': vpcId } - } - } - ], - 'Compliance': { - 'Status': 'PASSED', - 'RelatedRequirements': [ - 'NIST CSF DE.AE-3', - 'NIST SP 800-53 AU-6', - 'NIST SP 800-53 CA-7', - 'NIST SP 800-53 IR-4', - 'NIST SP 800-53 IR-5', - 'NIST SP 800-53 IR-8', - 'NIST SP 800-53 SI-4', - 'AICPA TSC CC7.2', - 'ISO 27001:2013 A.12.4.1', - 'ISO 27001:2013 A.16.1.7' - ] - }, - 'Workflow': { - 'Status': 'RESOLVED' - }, - 'RecordState': 'ARCHIVED' - } - yield finding diff --git a/auditors/Amazon_WorkSpaces_Auditor.py b/auditors/Amazon_WorkSpaces_Auditor.py deleted file mode 100644 index d553cb14..00000000 --- a/auditors/Amazon_WorkSpaces_Auditor.py +++ /dev/null @@ -1,596 +0,0 @@ -# This file is part of ElectricEye. - -# ElectricEye is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# ElectricEye is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License along with ElectricEye. -# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. - -import boto3 -import os -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -workspaces = boto3.client("workspaces") -# create env vars -awsRegion = os.environ["AWS_REGION"] -awsAccountId = sts.get_caller_identity()["Account"] -# loop through workspaces -try: - response = workspaces.describe_workspaces() - myWorkSpaces = response["Workspaces"] -except: - response = "" - myWorkSpaces = "" - - -class WorkspacesUserVolumeEncryptionCheck(Auditor): - def execute(self): - for workspace in myWorkSpaces: - workspaceId = str(workspace["WorkspaceId"]) - workspaceArn = ( - "arn:aws:workspaces:" - + awsRegion - + ":" - + awsAccountId - + ":workspace/" - + workspaceId - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - userVolumeEncryptionCheck = str( - workspace["UserVolumeEncryptionEnabled"] - ) - if userVolumeEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-user-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[WorkSpaces.1] WorkSpaces should have user volume encryption enabled", - "Description": "Workspace " - + workspaceId - + " does not have user volume encryption enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-user-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[WorkSpaces.1] WorkSpaces should have user volume encryption enabled", - "Description": "Workspace " - + workspaceId - + " has user volume encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class WorkspacesRootVolumeEncryptionCheck(Auditor): - def execute(self): - for workspace in myWorkSpaces: - workspaceId = str(workspace["WorkspaceId"]) - workspaceArn = ( - "arn:aws:workspaces:" - + awsRegion - + ":" - + awsAccountId - + ":workspace/" - + workspaceId - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - rootVolumeEncryptionCheck = str( - workspace["RootVolumeEncryptionEnabled"] - ) - if rootVolumeEncryptionCheck == "False": - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-root-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "HIGH"}, - "Confidence": 99, - "Title": "[WorkSpaces.1] WorkSpaces should have root volume encryption enabled", - "Description": "Workspace " - + workspaceId - + " does not have root volume encryption enabled. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-root-volume-encryption-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices", - "Effects/Data Exposure", - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[WorkSpaces.1] WorkSpaces should have root volume encryption enabled", - "Description": "Workspace " - + workspaceId - + " does not have root volume encryption enabled.", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.DS-1", - "NIST SP 800-53 MP-8", - "NIST SP 800-53 SC-12", - "NIST SP 800-53 SC-28", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.2.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - except Exception as e: - print(e) - - -class WorkspacesRunningModeCheck(Auditor): - def execute(self): - for workspace in myWorkSpaces: - workspaceId = str(workspace["WorkspaceId"]) - workspaceArn = ( - "arn:aws:workspaces:" - + awsRegion - + ":" - + awsAccountId - + ":workspace/" - + workspaceId - ) - runningModeCheck = str(workspace["WorkspaceProperties"]["RunningMode"]) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if runningModeCheck != "AUTO_STOP": - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-auto-stop-running-mode-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "LOW"}, - "Confidence": 99, - "Title": "[WorkSpaces.3] WorkSpaces should be configured to auto stop after inactivity", - "Description": "Workspace " - + workspaceId - + " does not have its running mode configured to auto-stop. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces running modes and how to auto-stop refer to the Manage the WorkSpace Running Mode section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/running-mode.html#stop-start-workspace", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspaceArn + "/workspaces-auto-stop-running-mode-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspaceArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[WorkSpaces.3] WorkSpaces should be configured to auto stop after inactivity", - "Description": "Workspace " - + workspaceId - + " has its running mode configured to auto-stop.", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces running modes and how to auto-stop refer to the Manage the WorkSpace Running Mode section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/running-mode.html#stop-start-workspace", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsWorkspacesWorkspace", - "Id": workspaceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"WorkspaceId": workspaceId}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.AM-2", - "NIST SP 800-53 CM-8", - "NIST SP 800-53 PM-5", - "AICPA TSC CC3.2", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.8.1.1", - "ISO 27001:2013 A.8.1.2", - "ISO 27001:2013 A.12.5.1", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - - -class WorkspacesDirectoryDefaultInternetCheck(Auditor): - def execute(self): - response = workspaces.describe_workspace_directories() - for directory in response["Directories"]: - workspacesDirectoryId = str(directory["DirectoryId"]) - workspacesDirectoryArn = ( - "arn:aws:workspaces:" - + awsRegion - + ":" - + awsAccountId - + ":directory/" - + workspacesDirectoryId - ) - internetAccessCheck = str( - directory["WorkspaceCreationProperties"]["EnableInternetAccess"] - ) - iso8601Time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if internetAccessCheck == "True": - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspacesDirectoryArn - + "/workspaces-directory-default-internet-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspacesDirectoryArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "MEDIUM"}, - "Confidence": 99, - "Title": "[WorkSpaces.4] WorkSpaces Directories should not be configured to provide default internet access", - "Description": "Workspace directory " - + workspacesDirectoryId - + " provides default internet access to WorkSpaces. Refer to the remediation instructions to remediate this behavior", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces internet access refer to the Provide Internet Access from Your WorkSpace section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.amazonaws.cn/en_us/workspaces/latest/adminguide/amazon-workspaces-internet-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": workspacesDirectoryArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"DirectoryId": workspacesDirectoryId} - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": workspacesDirectoryArn - + "/workspaces-directory-default-internet-access-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": workspacesDirectoryArn, - "AwsAccountId": awsAccountId, - "Types": [ - "Software and Configuration Checks/AWS Security Best Practices" - ], - "FirstObservedAt": iso8601Time, - "CreatedAt": iso8601Time, - "UpdatedAt": iso8601Time, - "Severity": {"Label": "INFORMATIONAL"}, - "Confidence": 99, - "Title": "[WorkSpaces.4] WorkSpaces Directories should not be configured to provide default internet access", - "Description": "Workspace directory " - + workspacesDirectoryId - + " does not provide default internet access to WorkSpaces.", - "Remediation": { - "Recommendation": { - "Text": "For more information on WorkSpaces internet access refer to the Provide Internet Access from Your WorkSpace section of the Amazon WorkSpaces Administrator Guide", - "Url": "https://docs.amazonaws.cn/en_us/workspaces/latest/adminguide/amazon-workspaces-internet-access.html", - } - }, - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "Other", - "Id": workspacesDirectoryArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": {"DirectoryId": workspacesDirectoryId} - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF PR.AC-5", - "NIST SP 800-53 AC-4", - "NIST SP 800-53 AC-10", - "NIST SP 800-53 SC-7", - "AICPA TSC CC6.1", - "ISO 27001:2013 A.13.1.1", - "ISO 27001:2013 A.13.1.3", - "ISO 27001:2013 A.13.2.1", - "ISO 27001:2013 A.14.1.2", - "ISO 27001:2013 A.14.1.3", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding diff --git a/auditors/Auditor.py b/auditors/Auditor.py deleted file mode 100644 index 1f939ba1..00000000 --- a/auditors/Auditor.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Auditor plugin manager - -This module implements a plugin manager for ElectricEye auditors. It consists of two parts: - The base Auditor class that ever auditor check must inherit from - The AuditorCollection that loads the plugins from the plugin directory - -Example usage: - Create a list of auditor checks by passing the relative package name where the plugins reside: - auditors = AuditorCollection("auditors") - This will return a list of dictionaries: - { - "check": , - "auditor": - } -""" - -import inspect -import os -import pkgutil -import importlib - - -class Auditor(object): - """Base class that each auditor must inherit from. - Every auditor must implement an execute method. - """ - - def __init__(self): - self.description = "UNKNOWN" - self.name = self.__class__.__name__ - - def execute(self, *args, **kwargs): - """The method that we expect all plugins to implement. This is the - method that our framework will call - """ - raise NotImplementedError - - -class AuditorCollection(object): - """Upon creation, this class will read the plugins package for modules - that contain a class definition that is inheriting from the Auditor class - """ - - def __init__(self, plugin_package): - """Constructor that initiates the reading of all available plugins - when an instance of the PluginCollection object is created - """ - self.plugin_package = plugin_package - self.reload_plugins() - - def reload_plugins(self): - """Reset the list of all plugins and initiate the walk over the main - provided plugin package to load all available plugins - """ - self.plugins = [] - self.walk_package(self.plugin_package) - - def walk_package(self, package): - """Load all modules in package to retrieve all plugins - """ - imported_package = __import__(package) - - for _, pluginname, ispkg in pkgutil.iter_modules( - imported_package.__path__, imported_package.__name__ + "." - ): - try: - if not ispkg: - plugin_module = importlib.import_module(pluginname) - clsmembers = inspect.getmembers(plugin_module, inspect.isclass) - for (_, c) in clsmembers: - # Only add classes that are a sub class of Auditor, but NOT Auditor itself - if issubclass(c, Auditor) & (c is not Auditor): - self.plugins.append( - {"check": c(), "auditor": pluginname,} - ) - except Exception as e: - print(f"failed to load {pluginname} with error {e}") diff --git a/auditors/Shodan_Auditor.py b/auditors/Shodan_Auditor.py deleted file mode 100644 index c31a6184..00000000 --- a/auditors/Shodan_Auditor.py +++ /dev/null @@ -1,1294 +0,0 @@ -import boto3 -import os -import requests -import socket -import json -import datetime -from auditors.Auditor import Auditor - -# import boto3 clients -sts = boto3.client("sts") -ssm = boto3.client("ssm") -ec2 = boto3.client("ec2") -elbv2 = boto3.client("elbv2") -rds = boto3.client("rds") -elasticsearch = boto3.client("es") -elb = boto3.client("elb") -dms = boto3.client("dms") -amzmq = boto3.client("mq") - -# create env vars -awsAccountId = sts.get_caller_identity()["Account"] -awsRegion = os.environ["AWS_REGION"] -try: - apiKeyParam = os.environ["SHODAN_API_KEY_PARAM"] -except Exception as e: - apiKeyParam = "" - print(e) - - -# Shodan information for Requests -shodanUrl = "https://api.shodan.io/shodan/host/" -try: - response = ssm.get_parameter(Name=apiKeyParam, WithDecryption=True) - shodanApiKey = str(response["Parameter"]["Value"]) -except Exception as e: - print(e) - - -class PublicEC2ShodanCheck(Auditor): - def execute(self): - try: - response = ec2.describe_instances(DryRun=False, MaxResults=500) - for res in response["Reservations"]: - for inst in res["Instances"]: - ec2Type = str(inst["InstanceType"]) - ec2AmiId = str(inst["ImageId"]) - ec2Id = str(inst["InstanceId"]) - ec2Arn = ( - "arn:aws:ec2:" - + awsRegion - + ":" - + awsAccountId - + "instance/" - + ec2Id - ) - ec2PrivateIp = str(inst["PrivateIpAddress"]) - ec2VpcId = str(inst["VpcId"]) - ec2SubnetId = str(inst["SubnetId"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - ec2PublicIp = str(inst["PublicIpAddress"]) - # use requests Library to check the Shodan index for your host - r = requests.get( - url=shodanUrl + ec2PublicIp + "?key=" + shodanApiKey - ) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": ec2Arn - + "/" - + ec2PublicIp - + "/ec2-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ec2Arn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.EC2.1] EC2 instances with public IP addresses should be monitored for being indexed by Shodan", - "Description": "EC2 instance " - + ec2Id - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": ec2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": ec2Type, - "ImageId": ec2AmiId, - "IpV4Addresses": [ - ec2PublicIp, - ec2PrivateIp, - ], - "VpcId": ec2VpcId, - "SubnetId": ec2SubnetId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": ec2Arn - + "/" - + ec2PublicIp - + "/ec2-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": ec2Arn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.EC2.1] EC2 instances with public IP addresses should be monitored for being indexed by Shodan", - "Description": "EC2 instance " - + ec2Id - + " has been indexed by Shodan on IP address " - + ec2PublicIp - + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your host.", - "SourceUrl": "https://www.shodan.io/host/" - + ec2PublicIp, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": ec2PublicIp, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" - + ec2PublicIp, - }, - ], - "Resources": [ - { - "Type": "AwsEc2Instance", - "Id": ec2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsEc2Instance": { - "Type": ec2Type, - "ImageId": ec2AmiId, - "IpV4Addresses": [ - ec2PublicIp, - ec2PrivateIp, - ], - "VpcId": ec2VpcId, - "SubnetId": ec2SubnetId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - except Exception as e: - if str(e) == "'PublicIpAddress'": - print( - ec2Id + " does not have a Public IPv4 Address, skipping" - ) - pass - else: - print(e) - except Exception as e: - print(e) - - -class PublicALBShodanCheck(Auditor): - def execute(self): - try: - response = elbv2.describe_load_balancers() - for lbs in response["LoadBalancers"]: - elbv2Scheme = str(lbs["Scheme"]) - elbv2Type = str(lbs["Type"]) - elbv2Name = str(lbs["LoadBalancerName"]) - elbv2Arn = str(lbs["LoadBalancerArn"]) - elbv2Vpc = str(lbs["VpcId"]) - elbv2Dns = str(lbs["DNSName"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if elbv2Scheme == "internet-facing" and elbv2Type == "application": - # use Socket to do a DNS lookup and retrieve the IP address - elbv2Ip = socket.gethostbyname(elbv2Dns) - # use requests Library to check the Shodan index for your host - r = requests.get(url=shodanUrl + elbv2Ip + "?key=" + shodanApiKey) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/" + elbv2Dns + "/alb-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.ELBv2.1] Internet-facing Application Load Balancers should be monitored for being indexed by Shodan", - "Description": "ALB " - + elbv2Name - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2Dns, - "Scheme": elbv2Scheme, - "Type": elbv2Type, - "VpcId": elbv2Vpc, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": elbv2Arn + "/" + elbv2Dns + "/alb-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": elbv2Arn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.ELBv2.1] Internet-facing Application Load Balancers should be monitored for being indexed by Shodan", - "Description": "ALB " - + elbv2Name - + " has been indexed by Shodan on IP address " - + elbv2Ip - + " from DNS name " - + elbv2Dns - + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your load balancer.", - "SourceUrl": "https://www.shodan.io/host/" + elbv2Ip, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": elbv2Ip, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" - + elbv2Ip, - }, - ], - "Resources": [ - { - "Type": "AwsElbv2LoadBalancer", - "Id": elbv2Arn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElbv2LoadBalancer": { - "DNSName": elbv2Dns, - "Scheme": elbv2Scheme, - "Type": elbv2Type, - "VpcId": elbv2Vpc, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print( - elbv2Name + " is not an ALB or is not internet-facing, skipping" - ) - except Exception as e: - print(e) - - -class PublicRDSShodanCheck(Auditor): - def execute(self): - try: - response = rds.describe_db_instances() - for rdsdb in response["DBInstances"]: - rdsInstanceId = str(rdsdb["DBInstanceIdentifier"]) - rdsInstanceArn = str(rdsdb["DBInstanceArn"]) - rdsInstanceClass = str(rdsdb["DBInstanceClass"]) - rdsDbiRescId = str(rdsdb["DbiResourceId"]) - rdsEngine = str(rdsdb["Engine"]) - rdsEngineVersion = str(rdsdb["EngineVersion"]) - rdsDns = str(rdsdb["Endpoint"]["Address"]) - publicCheck = str(rdsdb["PubliclyAccessible"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if publicCheck == "True": - # use Socket to do a DNS lookup and retrieve the IP address - rdsIp = socket.gethostbyname(rdsDns) - # use requests Library to check the Shodan index for your host - r = requests.get(url=shodanUrl + rdsIp + "?key=" + shodanApiKey) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": rdsInstanceArn - + "/" - + rdsDns - + "/rds-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": rdsInstanceArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.RDS.1] Public accessible RDS instances should be monitored for being indexed by Shodan", - "Description": "RDS instance " - + rdsInstanceId - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": rdsInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": rdsInstanceId, - "DBInstanceClass": rdsInstanceClass, - "DbiResourceId": rdsDbiRescId, - "Engine": rdsEngine, - "EngineVersion": rdsEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": rdsInstanceArn - + "/" - + rdsDns - + "/rds-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": rdsInstanceArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.RDS.1] Public accessible RDS instances should be monitored for being indexed by Shodan", - "Description": "RDS instance " - + rdsInstanceId - + " has been indexed by Shodan on IP address " - + rdsIp - + " from DNS name " - + rdsDns - + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your database.", - "SourceUrl": "https://www.shodan.io/host/" + rdsIp, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": rdsIp, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" + rdsIp, - }, - ], - "Resources": [ - { - "Type": "AwsRdsDbInstance", - "Id": rdsInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsRdsDbInstance": { - "DBInstanceIdentifier": rdsInstanceId, - "DBInstanceClass": rdsInstanceClass, - "DbiResourceId": rdsDbiRescId, - "Engine": rdsEngine, - "EngineVersion": rdsEngineVersion, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(rdsInstanceId + " is not Publicly Accessible, skipping") - except Exception as e: - print(e) - - -class PublicESDomainShodanCheck(Auditor): - def execute(self): - try: - response = elasticsearch.list_domain_names() - for domain in response["DomainNames"]: - esDomain = str(domain["DomainName"]) - try: - response = elasticsearch.describe_elasticsearch_domain( - DomainName=esDomain - ) - esDomainId = str(response["DomainStatus"]["DomainId"]) - esDomainName = str(response["DomainStatus"]["DomainName"]) - esDomainArn = str(response["DomainStatus"]["ARN"]) - esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) - esDomainEndpoint = str(response["DomainStatus"]["Endpoint"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - try: - esVpcOptions = str(response["DomainStatus"]["VPCOptions"]) - print(esDomainId + " is in a VPC, skipping") - pass - except Exception as e: - if str(e) == "'VPCOptions'": - # use Socket to do a DNS lookup and retrieve the IP address - esDomainIp = socket.gethostbyname(esDomainEndpoint) - # use requests Library to check the Shodan index for your host - r = requests.get( - url=shodanUrl + esDomainIp + "?key=" + shodanApiKey - ) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": esDomainArn - + "/" - + esDomainEndpoint - + "/elasticsearch-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": esDomainArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.Elasticsearch.1] ElasticSearch Service domains outside of a VPC should be monitored for being indexed by Shodan", - "Description": "ElasticSearch Service domain " - + esDomainName - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": esDomainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": esDomainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "Endpoint": esDomainEndpoint, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": esDomainArn - + "/" - + esDomainEndpoint - + "/elasticsearch-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": esDomainArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.Elasticsearch.1] ElasticSearch Service domains outside of a VPC should be monitored for being indexed by Shodan", - "Description": "ElasticSearch Service domain " - + esDomainName - + " has been indexed by Shodan on IP address " - + esDomainIp - + " from endpoint DNS name " - + esDomainEndpoint - + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your ES domain.", - "SourceUrl": "https://www.shodan.io/host/" - + esDomainIp, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": esDomainIp, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" - + esDomainIp, - }, - ], - "Resources": [ - { - "Type": "AwsElasticsearchDomain", - "Id": esDomainArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "AwsElasticsearchDomain": { - "DomainId": esDomainId, - "DomainName": esDomainName, - "ElasticsearchVersion": esVersion, - "Endpoint": esDomainEndpoint, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - print(e) - except Exception as e: - print(e) - except Exception as e: - print(e) - - -class PublicCLBShodanCheck(Auditor): - def execute(self): - try: - response = elb.describe_load_balancers() - for clbs in response["LoadBalancerDescriptions"]: - clbName = str(clbs["LoadBalancerName"]) - clbArn = ( - "arn:aws:elasticloadbalancing:" - + awsRegion - + ":" - + awsAccountId - + ":loadbalancer/" - + clbName - ) - clbDnsName = str(clbs["DNSName"]) - clbScheme = str(clbs["Scheme"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if clbScheme == "internet-facing": - # use Socket to do a DNS lookup and retrieve the IP address - clbIp = socket.gethostbyname(clbDnsName) - # use requests Library to check the Shodan index for your host - r = requests.get(url=shodanUrl + clbIp + "?key=" + shodanApiKey) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn - + "/" - + clbDnsName - + "/classic-load-balancer-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.ELB.1] Internet-facing Classic Load Balancers should be monitored for being indexed by Shodan", - "Description": "ElasticSearch Service domain " - + clbName - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": clbArn - + "/" - + clbDnsName - + "/classic-load-balancer-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": clbArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.ELB.1] Internet-facing Classic Load Balancers should be monitored for being indexed by Shodan", - "Description": "CLB " - + clbName - + " has been indexed by Shodan on IP address " - + clbIp - + " from DNS name " - + clbDnsName - + ". Review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your load balancer.", - "SourceUrl": "https://www.shodan.io/host/" + clbIp, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": clbIp, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" + clbIp, - }, - ], - "Resources": [ - { - "Type": "AwsElbLoadBalancer", - "Id": clbArn, - "Partition": "aws", - "Region": awsRegion, - "Details": {"Other": {"LoadBalancerName": clbName}}, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - pass - except Exception as e: - print(e) - - -class PublicDMSReplicationInstanceShodanCheck(Auditor): - def execute(self): - try: - response = dms.describe_replication_instances() - for repinstances in response["ReplicationInstances"]: - dmsInstanceId = str(repinstances["ReplicationInstanceIdentifier"]) - dmsInstanceArn = str(repinstances["ReplicationInstanceArn"]) - publicAccessCheck = str(repinstances["PubliclyAccessible"]) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if publicAccessCheck == "True": - dmsPublicIp = str( - repinstances["ReplicationInstancePublicIpAddress"] - ) - # use requests Library to check the Shodan index for your host - r = requests.get( - url=shodanUrl + dmsPublicIp + "?key=" + shodanApiKey - ) - data = r.json() - shodanOutput = str(data) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": dmsInstanceArn - + "/" - + dmsPublicIp - + "/dms-replication-instance-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": dmsInstanceArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.DMS.1] Publicly accessible Database Migration Service (DMS) Replication Instances should be monitored for being indexed by Shodan", - "Description": "DMS Replication Instance " - + dmsInstanceId - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsDmsReplicationInstance", - "Id": dmsInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ReplicationInstanceId": dmsInstanceId - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": dmsInstanceArn - + "/" - + dmsPublicIp - + "/dms-replication-instance-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": dmsInstanceArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.DMS.1] Publicly accessible Database Migration Service (DMS) Replication Instances should be monitored for being indexed by Shodan", - "Description": "DMS Replication Instance " - + dmsInstanceId - + " has been indexed on IP address " - + dmsInstanceId - + " . Review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your replication instance.", - "SourceUrl": "https://www.shodan.io/host/" + dmsPublicIp, - "ProductFields": {"Product Name": "ElectricEye"}, - "ThreatIntelIndicators": [ - { - "Type": "IPV4_ADDRESS", - "Category": "EXPLOIT_SITE", - "Value": dmsPublicIp, - "LastObservedAt": iso8601time, - "Source": "Shodan.io", - "SourceUrl": "https://www.shodan.io/host/" - + dmsPublicIp, - }, - ], - "Resources": [ - { - "Type": "AwsDmsReplicationInstance", - "Id": dmsInstanceArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "ReplicationInstanceId": dmsInstanceId - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - pass - except Exception as e: - print(e) - - -class PublicAmazonmqBrokerShodanCheck(Auditor): - def execute(self): - try: - response = amzmq.list_brokers(MaxResults=100) - myBrokers = response["BrokerSummaries"] - for brokers in myBrokers: - brokerName = str(brokers["BrokerName"]) - try: - response = amzmq.describe_broker(BrokerId=brokerName) - brokerArn = str(response["BrokerArn"]) - brokerId = str(response["BrokerId"]) - publicAccessCheck = str(response["PubliclyAccessible"]) - if publicAccessCheck == "True": - mqInstances = response["BrokerInstances"] - for instance in mqInstances: - mqBrokerIpv4 = str(instance["IpAddress"]) - r = requests.get( - url=shodanUrl + mqBrokerIpv4 + "?key=" + shodanApiKey - ) - data = r.json() - shodanOutput = str(data) - iso8601time = ( - datetime.datetime.utcnow() - .replace(tzinfo=datetime.timezone.utc) - .isoformat() - ) - if ( - shodanOutput - == "{'error': 'No information available for that IP.'}" - ): - # this is a passing check - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn - + "/" - + mqBrokerIpv4 - + "/amazon-mq-broker-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "INFORMATIONAL"}, - "Title": "[Shodan.AmazonMQ.1] Publicly accessible Amazon MQ message brokers should be monitored for being indexed by Shodan", - "Description": "Amazon MQ message brokers " - + brokerName - + " has not been indexed by Shodan.", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "PASSED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "RESOLVED"}, - "RecordState": "ARCHIVED", - } - yield finding - else: - finding = { - "SchemaVersion": "2018-10-08", - "Id": brokerArn - + "/" - + mqBrokerIpv4 - + "/amazon-mq-broker-shodan-index-check", - "ProductArn": "arn:aws:securityhub:" - + awsRegion - + ":" - + awsAccountId - + ":product/" - + awsAccountId - + "/default", - "GeneratorId": brokerArn, - "AwsAccountId": awsAccountId, - "Types": ["Effects/Data Exposure"], - "CreatedAt": iso8601time, - "UpdatedAt": iso8601time, - "Severity": {"Label": "MEDIUM"}, - "Title": "[Shodan.AmazonMQ.1] Publicly accessible Amazon MQ message brokers should be monitored for being indexed by Shodan", - "Description": "Amazon MQ message brokers " - + brokerName - + " has been indexed by Shodan on IP address " - + mqBrokerIpv4 - + ".", - "ProductFields": {"Product Name": "ElectricEye"}, - "Resources": [ - { - "Type": "AwsMqMessageBroker", - "Id": brokerArn, - "Partition": "aws", - "Region": awsRegion, - "Details": { - "Other": { - "brokerName": brokerName, - "brokerId": brokerId, - } - }, - } - ], - "Compliance": { - "Status": "FAILED", - "RelatedRequirements": [ - "NIST CSF ID.RA-2", - "NIST CSF DE.AE-2", - "NIST SP 800-53 AU-6", - "NIST SP 800-53 CA-7", - "NIST SP 800-53 IR-4", - "NIST SP 800-53 PM-15", - "NIST SP 800-53 PM-16", - "NIST SP 800-53 SI-4", - "NIST SP 800-53 SI-5", - "AIPCA TSC CC3.2", - "AIPCA TSC CC7.2", - "ISO 27001:2013 A.6.1.4", - "ISO 27001:2013 A.12.4.1", - "ISO 27001:2013 A.16.1.1", - "ISO 27001:2013 A.16.1.4", - ], - }, - "Workflow": {"Status": "NEW"}, - "RecordState": "ACTIVE", - } - yield finding - else: - pass - except Exception as e: - print(e) - except Exception as e: - print(e) From e74fd7ad4634a32821eea7ebcf48cd5c6d7e612d Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Sat, 13 Jun 2020 21:41:08 -0500 Subject: [PATCH 3/7] initial implementation --- test.csv | 39 ++++++++ tests/test_AWS_Lambda_Auditor.py | 147 +++++++++++++++++++++++++++ tests/test_Amazon_SNS_Auditor.py | 167 +++++++++++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 test.csv create mode 100644 tests/test_AWS_Lambda_Auditor.py create mode 100644 tests/test_Amazon_SNS_Auditor.py diff --git a/test.csv b/test.csv new file mode 100644 index 00000000..f6406211 --- /dev/null +++ b/test.csv @@ -0,0 +1,39 @@ +Id,Title,ProductArn,AwsAccountId,Severity,Confidence,Description,RecordState,Compliance Status,Remediation Recommendation,Remediation Recommendation Link +arn:aws:lambda:us-east-1:057637124865:function:cacheMe/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function cacheMe has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:workflow-callback/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function workflow-callback has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:test_async/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function test_async has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:rules_engine/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function rules_engine has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:kinesis_event_writer/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function kinesis_event_writer has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-result_runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-result_runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:lambda-runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function lambda-runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-engine/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-engine has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:rock-paper-scissors/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function rock-paper-scissors has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:toSlack-dev-to_slack/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function toSlack-dev-to_slack has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-lambda_runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-lambda_runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:add/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function add has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:task-writer/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function task-writer has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:reservedCurrency/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function reservedCurrency has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:high-low/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function high-low has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:stock-picker-dev-stock-picker/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function stock-picker-dev-stock-picker has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:workflow-dev-app/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function workflow-dev-app has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:my-first-test/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function my-first-test has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:reddit-slackbot-dev-runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function reddit-slackbot-dev-runner has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-app/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-app has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration +arn:aws:sns:us-east-1:057637124865:action_responses/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic action_responses is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:actions/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic actions is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic cloudtrail-sns is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:core/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic core is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:dynamodb/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic dynamodb is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:pagerduty/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic pagerduty is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html +arn:aws:sns:us-east-1:057637124865:actions/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic actions does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit +arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic cloudtrail-sns does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit +arn:aws:sns:us-east-1:057637124865:core/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic core does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit +arn:aws:sns:us-east-1:057637124865:pagerduty/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic pagerduty does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit +arn:aws:sns:us-east-1:057637124865:pagerduty/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic pagerduty does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit +arn:aws:sns:us-east-1:057637124865:action_responses/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic action_responses does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible +arn:aws:sns:us-east-1:057637124865:actions/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic actions does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible +arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic cloudtrail-sns does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible +arn:aws:sns:us-east-1:057637124865:core/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic core does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible +arn:aws:sns:us-east-1:057637124865:dynamodb/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic dynamodb does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible +arn:aws:sns:us-east-1:057637124865:pagerduty/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic pagerduty does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible diff --git a/tests/test_AWS_Lambda_Auditor.py b/tests/test_AWS_Lambda_Auditor.py new file mode 100644 index 00000000..3963264d --- /dev/null +++ b/tests/test_AWS_Lambda_Auditor.py @@ -0,0 +1,147 @@ +import datetime +import os +import pytest +from botocore.stub import Stubber, ANY +from auditors.AWS_Lambda_Auditor import ( + FunctionUnusedCheck, + sts, + lambda_client, + cloudwatch, +) + +# not available in local testing without ECS +os.environ["AWS_REGION"] = "us-east-1" +# for local testing, don't assume default profile exists +os.environ["AWS_DEFAULT_REGION"] = "us-east-1" + +sts_response = { + "Account": "012345678901", + "Arn": "arn:aws:iam::012345678901:user/user", +} + +list_functions_response = { + "Functions": [ + { + "FunctionName": "lambda-runner", + "FunctionArn": "arn:aws:lambda:us-east-1:012345678901:function:lambda-runner", + "LastModified": "2019-05-02T22:00:23.807+0000", + }, + ], +} + +get_metric_data_params = { + "EndTime": ANY, + "MetricDataQueries": ANY, + "StartTime": ANY, +} + +get_metric_data_empty_response = { + "MetricDataResults": [ + { + "Id": "m1", + "Label": "Invocations", + "Timestamps": [], + "Values": [], + "StatusCode": "Complete", + } + ], +} + +get_metric_data_response = { + "MetricDataResults": [ + { + "Id": "m1", + "Label": "Invocations", + "Timestamps": [datetime.datetime.now(datetime.timezone.utc)], + "Values": [3.0,], + "StatusCode": "Complete", + } + ], +} + + +@pytest.fixture(scope="function") +def sts_stubber(): + sts_stubber = Stubber(sts) + sts_stubber.activate() + yield sts_stubber + sts_stubber.deactivate() + + +@pytest.fixture(scope="function") +def lambda_stubber(): + lambda_stubber = Stubber(lambda_client) + lambda_stubber.activate() + yield lambda_stubber + lambda_stubber.deactivate() + + +@pytest.fixture(scope="function") +def cloudwatch_stubber(): + cloudwatch_stubber = Stubber(cloudwatch) + cloudwatch_stubber.activate() + yield cloudwatch_stubber + cloudwatch_stubber.deactivate() + + +def test_recent_use_lambda(lambda_stubber, cloudwatch_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + lambda_stubber.add_response("list_functions", list_functions_response) + cloudwatch_stubber.add_response( + "get_metric_data", get_metric_data_response, get_metric_data_params + ) + check = FunctionUnusedCheck() + results = check.execute() + for result in results: + if "lambda-runner" in result["Id"]: + assert result["RecordState"] == "ARCHIVED" + else: + assert False + lambda_stubber.assert_no_pending_responses() + cloudwatch_stubber.assert_no_pending_responses() + + +def test_no_activity_failure(lambda_stubber, cloudwatch_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + lambda_stubber.add_response("list_functions", list_functions_response) + cloudwatch_stubber.add_response( + "get_metric_data", get_metric_data_empty_response, get_metric_data_params + ) + check = FunctionUnusedCheck() + results = check.execute() + for result in results: + if "lambda-runner" in result["Id"]: + assert result["RecordState"] == "ACTIVE" + else: + assert False + lambda_stubber.assert_no_pending_responses() + cloudwatch_stubber.assert_no_pending_responses() + + +def test_recently_updated(lambda_stubber, cloudwatch_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + list_functions_recent_update_response = { + "Functions": [ + { + "FunctionName": "lambda-runner", + "FunctionArn": "arn:aws:lambda:us-east-1:012345678901:function:lambda-runner", + "LastModified": ( + datetime.datetime.now(datetime.timezone.utc) + - datetime.timedelta(days=1) + ).isoformat(), + }, + ], + } + lambda_stubber.add_response("list_functions", list_functions_recent_update_response) + cloudwatch_stubber.add_response( + "get_metric_data", get_metric_data_empty_response, get_metric_data_params + ) + check = FunctionUnusedCheck() + results = check.execute() + for result in results: + if "lambda-runner" in result["Id"]: + assert result["RecordState"] == "ARCHIVED" + else: + assert False + lambda_stubber.assert_no_pending_responses() + cloudwatch_stubber.assert_no_pending_responses() diff --git a/tests/test_Amazon_SNS_Auditor.py b/tests/test_Amazon_SNS_Auditor.py new file mode 100644 index 00000000..430b3db5 --- /dev/null +++ b/tests/test_Amazon_SNS_Auditor.py @@ -0,0 +1,167 @@ +import datetime +import json +import os +import pytest +from botocore.stub import Stubber, ANY +from auditors.Amazon_SNS_Auditor import ( + SNSTopicEncryptionCheck, + SNSHTTPEncryptionCheck, + SNSPublicAccessCheck, + SNSCrossAccountCheck, + sts, + sns, +) + +# not available in local testing without ECS +os.environ["AWS_REGION"] = "us-east-1" +# for local testing, don't assume default profile exists +os.environ["AWS_DEFAULT_REGION"] = "us-east-1" + +sts_response = { + "Account": "012345678901", + "Arn": "arn:aws:iam::012345678901:user/user", +} + +list_topics_response = { + "Topics": [{"TopicArn": "arn:aws:sns:us-east-1:012345678901:MyTopic"},], +} + +get_topic_attributes_arn_response = { + "Attributes": { + "Policy": '{"Statement":[{"Principal":{"AWS":"arn:aws:iam::012345678901:root"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', + } +} +get_topic_attributes_only_id_response = { + "Attributes": { + "Policy": '{"Statement":[{"Principal":{"AWS":"012345678901"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', + } +} + +get_topic_attributes_wrong_id_response = { + "Attributes": { + "Policy": '{"Statement":[{"Principal":{"AWS":"arn:aws:iam::012345678902:root"},"Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}', + } +} + +get_topic_attributes_response1 = { + "Attributes": { + "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"arn:aws:iam::012345678901:root"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test"}]}' + } +} + +get_topic_attributes_response2 = { + "Attributes": { + "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic","SNS:Subscribe","SNS:ListSubscriptionsByTopic","SNS:Publish","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test","Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}}]}' + } +} + +get_topic_attributes_response3 = { + "Attributes": { + "Policy": '{"Version":"2008-10-17","Id":"__default_policy_ID","Statement":[{"Sid":"__default_statement_ID","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:Publish","SNS:RemovePermission","SNS:SetTopicAttributes","SNS:DeleteTopic","SNS:ListSubscriptionsByTopic","SNS:GetTopicAttributes","SNS:Receive","SNS:AddPermission","SNS:Subscribe"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test","Condition":{"StringEquals":{"AWS:SourceOwner":"012345678901"}}},{"Sid":"__console_pub_0","Effect":"Allow","Principal":{"AWS":"*"},"Action":"SNS:Publish","Resource":"arn:aws:sns:us-east-1:012345678901:Test"},{"Sid":"__console_sub_0","Effect":"Allow","Principal":{"AWS":"*"},"Action":["SNS:Subscribe","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:012345678901:Test"}]}' + } +} + + +@pytest.fixture(scope="function") +def sts_stubber(): + sts_stubber = Stubber(sts) + sts_stubber.activate() + yield sts_stubber + sts_stubber.deactivate() + + +@pytest.fixture(scope="function") +def sns_stubber(): + sns_stubber = Stubber(sns) + sns_stubber.activate() + yield sns_stubber + sns_stubber.deactivate() + + +def test_id_arn_is_principal(sns_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response("get_topic_attributes", get_topic_attributes_arn_response) + check = SNSCrossAccountCheck() + results = check.execute() + for result in results: + if "MyTopic" in result["Id"]: + print(result["Id"]) + assert result["RecordState"] == "ARCHIVED" + else: + assert False + sns_stubber.assert_no_pending_responses() + + +def test_id_is_principal(sns_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response( + "get_topic_attributes", get_topic_attributes_only_id_response + ) + check = SNSCrossAccountCheck() + results = check.execute() + for result in results: + if "MyTopic" in result["Id"]: + print(result["Id"]) + assert result["RecordState"] == "ARCHIVED" + else: + assert False + sns_stubber.assert_no_pending_responses() + + +def test_id_not_principal(sns_stubber, sts_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response( + "get_topic_attributes", get_topic_attributes_wrong_id_response + ) + check = SNSCrossAccountCheck() + results = check.execute() + for result in results: + if "MyTopic" in result["Id"]: + print(result["Id"]) + assert result["RecordState"] == "ACTIVE" + sns_stubber.assert_no_pending_responses() + + +def test_no_access(sts_stubber, sns_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response1) + check = SNSPublicAccessCheck() + results = check.execute() + for result in results: + if "Test" in result["Id"]: + assert result["RecordState"] == "ARCHIVED" + else: + assert False + sns_stubber.assert_no_pending_responses() + + +def test_has_a_condition(sts_stubber, sns_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response2) + check = SNSPublicAccessCheck() + results = check.execute() + for result in results: + if "Test" in result["Id"]: + assert result["RecordState"] == "ARCHIVED" + else: + assert False + sns_stubber.assert_no_pending_responses() + + +def test_has_public_access(sts_stubber, sns_stubber): + sts_stubber.add_response("get_caller_identity", sts_response) + sns_stubber.add_response("list_topics", list_topics_response) + sns_stubber.add_response("get_topic_attributes", get_topic_attributes_response3) + check = SNSPublicAccessCheck() + results = check.execute() + for result in results: + if "Test" in result["Id"]: + assert result["RecordState"] == "ARCHIVED" + else: + assert False + sns_stubber.assert_no_pending_responses() From 43761c01509a8fc41c4990cafdff5a4d29fc7fb7 Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Mon, 15 Jun 2020 15:20:40 -0500 Subject: [PATCH 4/7] registry for functions --- test.csv | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 test.csv diff --git a/test.csv b/test.csv deleted file mode 100644 index f6406211..00000000 --- a/test.csv +++ /dev/null @@ -1,39 +0,0 @@ -Id,Title,ProductArn,AwsAccountId,Severity,Confidence,Description,RecordState,Compliance Status,Remediation Recommendation,Remediation Recommendation Link -arn:aws:lambda:us-east-1:057637124865:function:cacheMe/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function cacheMe has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:workflow-callback/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function workflow-callback has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:test_async/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function test_async has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:rules_engine/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function rules_engine has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:kinesis_event_writer/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function kinesis_event_writer has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-result_runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-result_runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:lambda-runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function lambda-runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-engine/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-engine has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:rock-paper-scissors/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function rock-paper-scissors has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:toSlack-dev-to_slack/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function toSlack-dev-to_slack has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-lambda_runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-lambda_runner has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:add/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function add has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:task-writer/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function task-writer has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:reservedCurrency/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function reservedCurrency has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:high-low/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function high-low has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:stock-picker-dev-stock-picker/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function stock-picker-dev-stock-picker has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:workflow-dev-app/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function workflow-dev-app has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:my-first-test/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function my-first-test has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:reddit-slackbot-dev-runner/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,Lambda function reddit-slackbot-dev-runner has been used or updated in the last 30 days.,ARCHIVED,PASSED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-app/lambda-function-unused-check,[Lambda.1] Lambda functions should be deleted after 30 days of no use,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,LOW,99,Lambda function serverless-flask-dev-app has not been used or updated in the last 30 days.,ACTIVE,FAILED,For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide,https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration -arn:aws:sns:us-east-1:057637124865:action_responses/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic action_responses is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:actions/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic actions is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic cloudtrail-sns is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:core/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic core is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:dynamodb/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic dynamodb is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:pagerduty/sns-topic-encryption-check,[SNS.1] SNS topics should be encrypted,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,HIGH,99,SNS topic pagerduty is not encrypted. Refer to the remediation instructions to remediate this behavior,ACTIVE,FAILED,For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html -arn:aws:sns:us-east-1:057637124865:actions/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic actions does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit -arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic cloudtrail-sns does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit -arn:aws:sns:us-east-1:057637124865:core/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic core does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit -arn:aws:sns:us-east-1:057637124865:pagerduty/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic pagerduty does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit -arn:aws:sns:us-east-1:057637124865:pagerduty/sns-http-subscription-check,[SNS.2] SNS topics should not use HTTP subscriptions,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,99,SNS topic pagerduty does not have a HTTP subscriber.,ARCHIVED,PASSED,For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit -arn:aws:sns:us-east-1:057637124865:action_responses/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic action_responses does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible -arn:aws:sns:us-east-1:057637124865:actions/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic actions does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible -arn:aws:sns:us-east-1:057637124865:cloudtrail-sns/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic cloudtrail-sns does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible -arn:aws:sns:us-east-1:057637124865:core/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic core does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible -arn:aws:sns:us-east-1:057637124865:dynamodb/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic dynamodb does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible -arn:aws:sns:us-east-1:057637124865:pagerduty/sns-public-access-check,[SNS.3] SNS topics should not have public access,arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default,057637124865,INFORMATIONAL,75,SNS topic pagerduty does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy,ARCHIVED,PASSED,For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.,https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible From c465eb2e2237ee74b9664953a9b5170e7290fe1f Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Mon, 15 Jun 2020 15:25:22 -0500 Subject: [PATCH 5/7] registry and plugins --- ElectricEye | 1 - eeauditor/auditors/AMI_Auditor.py | 282 ++ eeauditor/auditors/AWS_AppMesh_Auditor.py | 643 +++ eeauditor/auditors/AWS_Backup_Auditor.py | 722 +++ .../auditors/AWS_CloudFormation_Auditor.py | 271 ++ eeauditor/auditors/AWS_CloudTrail_Auditor.py | 597 +++ eeauditor/auditors/AWS_CodeBuild_Auditor.py | 775 ++++ eeauditor/auditors/AWS_DMS_Auditor.py | 387 ++ .../auditors/AWS_Directory_Service_Auditor.py | 291 ++ eeauditor/auditors/AWS_Glue_Auditor.py | 814 ++++ eeauditor/auditors/AWS_IAM_Auditor.py | 1106 +++++ .../auditors/AWS_License_Manager_Auditor.py | 162 + .../auditors/AWS_Secrets_Manager_Auditor.py | 329 ++ .../auditors/AWS_Security_Hub_Auditor.py | 170 + .../auditors/AWS_Security_Services_Auditor.py | 369 ++ .../auditors/Amazon_AppStream_Auditor.py | 542 +++ .../auditors/Amazon_CognitoIdP_Auditor.py | 541 +++ .../auditors/Amazon_DocumentDB_Auditor.py | 1330 ++++++ eeauditor/auditors/Amazon_EBS_Auditor.py | 885 ++++ eeauditor/auditors/Amazon_EC2_Auditor.py | 199 + eeauditor/auditors/Amazon_EC2_SSM_Auditor.py | 759 +++ .../Amazon_EC2_Security_Group_Auditor.py | 4068 +++++++++++++++++ eeauditor/auditors/Amazon_ECR_Auditor.py | 610 +++ eeauditor/auditors/Amazon_ECS_Auditor.py | 317 ++ eeauditor/auditors/Amazon_EFS_Auditor.py | 165 + eeauditor/auditors/Amazon_EKS_Auditor.py | 469 ++ eeauditor/auditors/Amazon_ELB_Auditor.py | 769 ++++ eeauditor/auditors/Amazon_ELBv2_Auditor.py | 1072 +++++ eeauditor/auditors/Amazon_EMR_Auditor.py | 1400 ++++++ .../Amazon_Elasticache_Redis_Auditor.py | 536 +++ .../Amazon_ElasticsearchService_Auditor.py | 1157 +++++ .../Amazon_Kinesis_Data_Streams_Auditor.py | 296 ++ .../Amazon_Kinesis_Firehose_Auditor.py | 176 + eeauditor/auditors/Amazon_MQ_Auditor.py | 773 ++++ eeauditor/auditors/Amazon_MSK_Auditor.py | 577 +++ .../Amazon_Managed_Blockchain_Auditor.py | 564 +++ eeauditor/auditors/Amazon_Neptune_Auditor.py | 750 +++ eeauditor/auditors/Amazon_RDS_Auditor.py | 1619 +++++++ eeauditor/auditors/Amazon_Redshift_Auditor.py | 513 +++ eeauditor/auditors/Amazon_S3_Auditor.py | 865 ++++ .../auditors/Amazon_SageMaker_Auditor.py | 662 +++ .../Amazon_Shield_Advanced_Auditor.py | 1222 +++++ eeauditor/auditors/Amazon_VPC_Auditor.py | 277 ++ .../auditors/Amazon_WorkSpaces_Auditor.py | 596 +++ eeauditor/auditors/Auditor.py | 77 + eeauditor/auditors/Shodan_Auditor.py | 1294 ++++++ eeauditor/auditors/aws/AWS_Lambda_Auditor.py | 166 + .../auditors/aws/Amazon_APIGW_Auditor.py | 1006 ++++ eeauditor/auditors/aws/Amazon_SNS_Auditor.py | 581 +++ eeauditor/check_register.py | 27 + eeauditor/controller.py | 154 + eeauditor/report.py | 57 + findings.json | 2209 +++++++++ 53 files changed, 36198 insertions(+), 1 deletion(-) delete mode 160000 ElectricEye create mode 100644 eeauditor/auditors/AMI_Auditor.py create mode 100644 eeauditor/auditors/AWS_AppMesh_Auditor.py create mode 100644 eeauditor/auditors/AWS_Backup_Auditor.py create mode 100644 eeauditor/auditors/AWS_CloudFormation_Auditor.py create mode 100644 eeauditor/auditors/AWS_CloudTrail_Auditor.py create mode 100644 eeauditor/auditors/AWS_CodeBuild_Auditor.py create mode 100644 eeauditor/auditors/AWS_DMS_Auditor.py create mode 100644 eeauditor/auditors/AWS_Directory_Service_Auditor.py create mode 100644 eeauditor/auditors/AWS_Glue_Auditor.py create mode 100644 eeauditor/auditors/AWS_IAM_Auditor.py create mode 100644 eeauditor/auditors/AWS_License_Manager_Auditor.py create mode 100644 eeauditor/auditors/AWS_Secrets_Manager_Auditor.py create mode 100644 eeauditor/auditors/AWS_Security_Hub_Auditor.py create mode 100644 eeauditor/auditors/AWS_Security_Services_Auditor.py create mode 100644 eeauditor/auditors/Amazon_AppStream_Auditor.py create mode 100644 eeauditor/auditors/Amazon_CognitoIdP_Auditor.py create mode 100644 eeauditor/auditors/Amazon_DocumentDB_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EBS_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EC2_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EC2_SSM_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EC2_Security_Group_Auditor.py create mode 100644 eeauditor/auditors/Amazon_ECR_Auditor.py create mode 100644 eeauditor/auditors/Amazon_ECS_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EFS_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EKS_Auditor.py create mode 100644 eeauditor/auditors/Amazon_ELB_Auditor.py create mode 100644 eeauditor/auditors/Amazon_ELBv2_Auditor.py create mode 100644 eeauditor/auditors/Amazon_EMR_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Elasticache_Redis_Auditor.py create mode 100644 eeauditor/auditors/Amazon_ElasticsearchService_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Kinesis_Data_Streams_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Kinesis_Firehose_Auditor.py create mode 100644 eeauditor/auditors/Amazon_MQ_Auditor.py create mode 100644 eeauditor/auditors/Amazon_MSK_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Managed_Blockchain_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Neptune_Auditor.py create mode 100644 eeauditor/auditors/Amazon_RDS_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Redshift_Auditor.py create mode 100644 eeauditor/auditors/Amazon_S3_Auditor.py create mode 100644 eeauditor/auditors/Amazon_SageMaker_Auditor.py create mode 100644 eeauditor/auditors/Amazon_Shield_Advanced_Auditor.py create mode 100644 eeauditor/auditors/Amazon_VPC_Auditor.py create mode 100644 eeauditor/auditors/Amazon_WorkSpaces_Auditor.py create mode 100644 eeauditor/auditors/Auditor.py create mode 100644 eeauditor/auditors/Shodan_Auditor.py create mode 100644 eeauditor/auditors/aws/AWS_Lambda_Auditor.py create mode 100644 eeauditor/auditors/aws/Amazon_APIGW_Auditor.py create mode 100644 eeauditor/auditors/aws/Amazon_SNS_Auditor.py create mode 100644 eeauditor/check_register.py create mode 100644 eeauditor/controller.py create mode 100644 eeauditor/report.py create mode 100644 findings.json diff --git a/ElectricEye b/ElectricEye deleted file mode 160000 index 52e54f05..00000000 --- a/ElectricEye +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 52e54f0511a34f3c13e7c197e72a2b8316cba81e diff --git a/eeauditor/auditors/AMI_Auditor.py b/eeauditor/auditors/AMI_Auditor.py new file mode 100644 index 00000000..5b7dbe14 --- /dev/null +++ b/eeauditor/auditors/AMI_Auditor.py @@ -0,0 +1,282 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +ec2 = boto3.client('ec2') +sts = boto3.client('sts') +# create account id & region variables +awsAccount = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# find AMIs created by the account +response = ec2.describe_images(Filters=[ { 'Name': 'owner-id','Values': [ awsAccount ] } ],DryRun=False) +myAmis = response['Images'] + +class PublicAMICheck(Auditor): + def execute(self): + for ami in myAmis: + imageId = str(ami['ImageId']) + amiArn = 'arn:aws:ec2:' + awsRegion + '::image/' + imageId + imageName = str(ami['Name']) + imageCreatedDate = str(ami['CreationDate']) + publicCheck = str(ami['Public']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if publicCheck == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': amiArn + '/public-ami', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': amiArn, + 'AwsAccountId': awsAccount, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'CRITICAL' }, + 'Confidence': 99, + 'Title': '[AMI.1] Self-managed Amazon Machine Images (AMIs) should not be public', + 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is exposed to the public. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your AMI is not intended to be public refer to the Sharing an AMI with Specific AWS Accounts section of the EC2 user guide', + 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharingamis-explicit.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': amiArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': amiArn + '/public-ami', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': amiArn, + 'AwsAccountId': awsAccount, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AMI.1] Self-managed Amazon Machine Images (AMIs) should not be public', + 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is private.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your AMI is not intended to be public refer to the Sharing an AMI with Specific AWS Accounts section of the EC2 user guide', + 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/sharingamis-explicit.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': amiArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'REVOKED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class EncryptedAMICheck(Auditor): + def execute(self): + for ami in myAmis: + imageId = str(ami['ImageId']) + amiArn = 'arn:aws:ec2:' + awsRegion + '::image/' + imageId + imageName = str(ami['Name']) + imageCreatedDate = str(ami['CreationDate']) + BlockDevices = ami['BlockDeviceMappings'] + for ebsmapping in BlockDevices: + encryptionCheck = str(ebsmapping['Ebs']['Encrypted']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if encryptionCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': amiArn + '/public-ami', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': amiArn, + 'AwsAccountId': awsAccount, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[AMI.2] Self-managed Amazon Machine Images (AMIs) should be encrypted', + 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is not encrypted. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your AMI should be encrypted refer to the Image-Copying Scenarios section of the EC2 user guide', + 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#AMI-encryption-copy' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': amiArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': amiArn + '/public-ami', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': amiArn, + 'AwsAccountId': awsAccount, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AMI.2] Self-managed Amazon Machine Images (AMIs) should be encrypted', + 'Description': 'Amazon Machine Image (AMI) ' + imageName + ' is encrypted.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your AMI should be encrypted refer to the Image-Copying Scenarios section of the EC2 user guide', + 'Url': 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIEncryption.html#AMI-encryption-copy' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': amiArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'imageId': imageId, 'imageCreatedDate': imageCreatedDate } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/AWS_AppMesh_Auditor.py b/eeauditor/auditors/AWS_AppMesh_Auditor.py new file mode 100644 index 00000000..9279ce2b --- /dev/null +++ b/eeauditor/auditors/AWS_AppMesh_Auditor.py @@ -0,0 +1,643 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +appmesh = boto3.client('appmesh') +sts = boto3.client('sts') +# create account id & region variables +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# loop through AWS App Mesh meshes +try: + response = appmesh.list_meshes() + myMesh = response['meshes'] +except Exception as e: + print(e) + +class AppmeshMeshEgressCheck(Auditor): + def execute(self): + for meshes in myMesh: + meshName = str(meshes['meshName']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = appmesh.describe_mesh(meshName=meshName) + meshArn = str(response['mesh']['metadata']['arn']) + egressSpecCheck = str(response['mesh']['spec']['egressFilter']['type']) + if egressSpecCheck != 'DROP_ALL': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': meshArn + '/appmesh-mesh-egress-filter-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': meshArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[AppMesh.1] App Mesh meshes should have the egress filter configured to DROP_ALL', + 'Description': 'App Mesh mesh ' + meshName + ' egress filter is not configured to DROP_ALL. Configuring the filter to DROP_ALL only allows egress to other resources in the mesh and to AWS SPNs for API Calls. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on egress filters refer to the EgressFilter Data Type section of the AWS App Mesh API Reference', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/APIReference/API_EgressFilter.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': meshArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': meshArn + '/appmesh-mesh-egress-filter-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': meshArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AppMesh.1] App Mesh meshes should have the egress filter configured to DROP_ALL', + 'Description': 'App Mesh mesh ' + meshName + ' egress filter is configured to DROP_ALL.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on egress filters refer to the EgressFilter Data Type section of the AWS App Mesh API Reference', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/APIReference/API_EgressFilter.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': meshArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class AppmeshVirtNodeBackendDefaultTLSpolicyCheck(Auditor): + def execute(self): + for meshes in myMesh: + meshName = str(meshes['meshName']) + try: + response = appmesh.list_virtual_nodes(meshName=meshName) + for nodes in response['virtualNodes']: + nodeName = str(nodes['virtualNodeName']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) + nodeArn = str(response['virtualNode']['metadata']['arn']) + backendDefaultsCheck = str(response['virtualNode']['spec']['backendDefaults']['clientPolicy']) + if backendDefaultsCheck == '{}': + # this is a type of failing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not have a backend default client policy configured. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-2', + 'NIST SP 800-53 SC-8', + 'NIST SP 800-53 SC-11', + 'NIST SP 800-53 SC-12', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.13.2.3', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + backendTlsEnforceCheck = str(response['virtualNode']['spec']['backendDefaults']['clientPolicy']['tls']['enforce']) + if backendTlsEnforceCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not enforce TLS in the default client policy. TLS will encrypt the traffic in between the Envoy virtual nodes in your mesh to offload the responsibility from your application code and will also terminate TLS for you. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-2', + 'NIST SP 800-53 SC-8', + 'NIST SP 800-53 SC-11', + 'NIST SP 800-53 SC-12', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.13.2.3', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-default-tls-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AppMesh.2] App Mesh virtual nodes should enforce TLS by default for all backends', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' enforces TLS in the default client policy.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-2', + 'NIST SP 800-53 SC-8', + 'NIST SP 800-53 SC-11', + 'NIST SP 800-53 SC-12', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.13.2.3', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + +class AppmeshVirtNodeListenerStrictTLScheck(Auditor): + def execute(self): + for meshes in myMesh: + meshName = str(meshes['meshName']) + try: + response = appmesh.list_virtual_nodes(meshName=meshName) + for nodes in response['virtualNodes']: + nodeName = str(nodes['virtualNodeName']) + try: + response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) + nodeArn = str(response['virtualNode']['metadata']['arn']) + for listeners in response['virtualNode']['spec']['listeners']: + tlsStrictCheck = str(listeners['tls']['mode']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if tlsStrictCheck != 'STRICT': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-listener-strict-tls-mode-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[AppMesh.3] App Mesh virtual node listeners should only accept connections with TLS enabled', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not enforce STRICT mode for listeners. Not setting a STRICT listener mode will accept non-encrypted connections to the listeners in the node. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-2', + 'NIST SP 800-53 SC-8', + 'NIST SP 800-53 SC-11', + 'NIST SP 800-53 SC-12', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.13.2.3', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-listener-strict-tls-mode-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AppMesh.3] App Mesh virtual node listeners should only accept connections with TLS enabled', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' enforces STRICT mode for listeners.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring TLS for virtual nodes refer to the Transport Layer Security (TLS) section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual-node-tls.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-2', + 'NIST SP 800-53 SC-8', + 'NIST SP 800-53 SC-11', + 'NIST SP 800-53 SC-12', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.13.2.3', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'tls'": + pass + else: + print(e) + except Exception as e: + print(e) + +class AppmeshLoggingCheck(Auditor): + def execute(self): + for meshes in myMesh: + meshName = str(meshes['meshName']) + try: + response = appmesh.list_virtual_nodes(meshName=meshName) + for nodes in response['virtualNodes']: + nodeName = str(nodes['virtualNodeName']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = appmesh.describe_virtual_node(meshName=meshName,virtualNodeName=nodeName) + nodeArn = str(response['virtualNode']['metadata']['arn']) + loggingCheck = str(response['virtualNode']['spec']['logging']) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-access-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[AppMesh.4] App Mesh virtual nodes should define an HTTP access log path to enable log exports for Envoy proxies', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' specifies a path for HTTP access logs.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring access logging for virtual nodes refer to the Creating a Virtual Node section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_nodes.html#vn-create-virtual-node' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName, + 'accessLogPath': loggingCheck + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'logging'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': nodeArn + '/appmesh-virtual-node-access-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': nodeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[AppMesh.4] App Mesh virtual nodes should define an HTTP access log path to enable log exports for Envoy proxies', + 'Description': 'App Mesh virtual node ' + nodeName + ' for the mesh ' + meshName + ' does not specify a path for HTTP access logs. Specifying a path will allow you to use Docker log drivers or otherwise to pipe logs out of Envoy to another service such as CloudWatch. Refer to the remediation instructions if this configuration is not intended.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring access logging for virtual nodes refer to the Creating a Virtual Node section of the AWS App Mesh User Guide', + 'Url': 'https://docs.aws.amazon.com/app-mesh/latest/userguide/virtual_nodes.html#vn-create-virtual-node' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': nodeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'meshName': meshName, + 'virtualNodeName': nodeName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + except Exception as e: + print(e) diff --git a/eeauditor/auditors/AWS_Backup_Auditor.py b/eeauditor/auditors/AWS_Backup_Auditor.py new file mode 100644 index 00000000..66fa52f7 --- /dev/null +++ b/eeauditor/auditors/AWS_Backup_Auditor.py @@ -0,0 +1,722 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +sts = boto3.client('sts') +ec2 = boto3.client('ec2') +dynamodb = boto3.client('dynamodb') +rds = boto3.client('rds') +efs = boto3.client('efs') +backup = boto3.client('backup') +# create env vars +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] + +class VolumeBackupCheck(Auditor): + def execute(self): + # loop through available or in-use ebs volumes + response = ec2.describe_volumes(Filters=[{'Name': 'status','Values': ['available', 'in-use']}]) + myEbsVolumes = response['Volumes'] + for volumes in myEbsVolumes: + volumeId = str(volumes['VolumeId']) + volumeArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + ':volume/' + volumeId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + # check if ebs volumes are backed up + response = backup.describe_protected_resource(ResourceArn=volumeArn) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': volumeArn + '/ebs-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': volumeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Backup.1] EBS volumes should be protected by AWS Backup', + 'Description': 'EBS volume ' + volumeId + ' is protected by AWS Backup', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Volume', + 'Id': volumeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'volumeId': volumeId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': volumeArn + '/ebs-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': volumeArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Backup.1] EBS volumes should be protected by AWS Backup', + 'Description': 'EBS volume ' + volumeId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EBS volumes', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Volume', + 'Id': volumeArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'volumeId': volumeId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class EC2BackupCheck(Auditor): + def execute(self): + # loop through ec2 instances + response = ec2.describe_instances(DryRun=False) + myReservations = response['Reservations'] + for reservations in myReservations: + myInstances = reservations['Instances'] + for instances in myInstances: + instanceId = str(instances['InstanceId']) + instanceType = str(instances['InstanceType']) + imageId = str(instances['ImageId']) + subnetId = str(instances['SubnetId']) + vpcId = str(instances['VpcId']) + instanceArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + ':instance/' + instanceId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + # check if ec2 instances are backed up + response = backup.describe_protected_resource(ResourceArn=instanceArn) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': instanceArn + '/ec2-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': instanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Backup.2] EC2 instances should be protected by AWS Backup', + 'Description': 'EC2 instance ' + instanceId + ' is protected by AWS Backup.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Instance', + 'Id': instanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsEc2Instance': { + 'Type': instanceType, + 'ImageId': imageId, + 'VpcId': vpcId, + 'SubnetId': subnetId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': instanceArn + '/ec2-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': instanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Backup.2] EC2 instances should be protected by AWS Backup', + 'Description': 'EC2 instance ' + instanceId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EC2 instances', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Instance', + 'Id': instanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsEc2Instance': { + 'Type': instanceType, + 'ImageId': imageId, + 'VpcId': vpcId, + 'SubnetId': subnetId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class ddbBackupCheck(Auditor): + def execute(self): + # loop through dynamodb tables + response = dynamodb.list_tables() + myDdbTables = response['TableNames'] + for tables in myDdbTables: + response = dynamodb.describe_table(TableName=tables) + tableArn = str(response['Table']['TableArn']) + tableName = str(response['Table']['TableName']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + # check if ddb tables are backed up + response = backup.describe_protected_resource(ResourceArn=tableArn) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': tableArn + '/dynamodb-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': tableArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Backup.3] DynamoDB tables should be protected by AWS Backup', + 'Description': 'DynamoDB table ' + tableName + ' is protected by AWS Backup.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsDynamoDbTable', + 'Id': tableArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'tableName': tableName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': tableArn + '/dynamodb-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': tableArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Backup.3] DynamoDB tables should be protected by AWS Backup', + 'Description': 'DynamoDB table ' + tableName + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for DynamoDB tables', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsDynamoDbTable', + 'Id': tableArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'tableName': tableName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class rdsBackupCheck(Auditor): + def execute(self): + # loop through rds db instances + response = rds.describe_db_instances( + Filters=[ + { + 'Name': 'engine', + 'Values': [ + 'aurora', + 'aurora-mysql', + 'aurora-postgresql', + 'mariadb', + 'mysql', + 'oracle-ee', + 'postgres', + 'sqlserver-ee', + 'sqlserver-se', + 'sqlserver-ex', + 'sqlserver-web' + ] + } + ], + MaxRecords=100 + ) + myRdsInstances = response['DBInstances'] + for databases in myRdsInstances: + dbArn = str(databases['DBInstanceArn']) + dbId = str(databases['DBInstanceIdentifier']) + dbEngine = str(databases['Engine']) + dbEngineVersion = str(databases['EngineVersion']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + # check if db instances are backed up + response = backup.describe_protected_resource(ResourceArn=dbArn) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dbArn + '/rds-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dbArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Backup.4] RDS database instances should be protected by AWS Backup', + 'Description': 'RDS database instance ' + dbId + ' is protected by AWS Backup.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsRdsDbInstance', + 'Id': dbArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsRdsDbInstance': { + 'DBInstanceIdentifier': dbId, + 'Engine': dbEngine, + 'EngineVersion': dbEngineVersion + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding={ + 'SchemaVersion': '2018-10-08', + 'Id': dbArn + '/rds-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dbArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Backup.4] RDS database instances should be protected by AWS Backup', + 'Description': 'RDS database instance ' + dbId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for RDS instances', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsRdsDbInstance', + 'Id': dbArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsRdsDbInstance': { + 'DBInstanceIdentifier': dbId, + 'Engine': dbEngine, + 'EngineVersion': dbEngineVersion + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class efsBackupCheck(Auditor): + def execute(self): + # loop through EFS file systems + response = efs.describe_file_systems() + myFileSys = response['FileSystems'] + for filesys in myFileSys: + fileSysId = str(filesys['FileSystemId']) + fileSysArn = 'arn:aws:elasticfilesystem:' + awsRegion + ':' + awsAccountId + ':file-system/' + fileSysId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + # check if db instances are backed up + response = backup.describe_protected_resource(ResourceArn=fileSysArn) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': fileSysArn + '/efs-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': fileSysArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Backup.5] EFS file systems should be protected by AWS Backup', + 'Description': 'EFS file system ' + fileSysId + ' is protected by AWS Backup.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsElasticFileSystem', + 'Id': fileSysArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'fileSystemId': fileSysId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': fileSysArn + '/efs-backups', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': fileSysArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Backup.5] EFS file systems should be protected by AWS Backup', + 'Description': 'EFS file system ' + fileSysId + ' is not protected by AWS Backup. Refer to the remediation instructions for information on ensuring disaster recovery and business continuity requirements are fulfilled for EFS file systems.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on creating scheduled backups refer to the Assign Resources to a Backup Plan section of the AWS Backup Developer Guide', + 'Url': 'https://docs.aws.amazon.com/aws-backup/latest/devguide/create-a-scheduled-backup.html#assign-resources-to-plan' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsElasticFileSystem', + 'Id': fileSysArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'fileSystemId': fileSysId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + \ No newline at end of file diff --git a/eeauditor/auditors/AWS_CloudFormation_Auditor.py b/eeauditor/auditors/AWS_CloudFormation_Auditor.py new file mode 100644 index 00000000..34ff51f3 --- /dev/null +++ b/eeauditor/auditors/AWS_CloudFormation_Auditor.py @@ -0,0 +1,271 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +cloudformation = boto3.client('cloudformation') +# create env vars for account and region +#awsRegion = os.environ['AWS_REGION'] +awsRegion = 'us-east-1' +awsAccountId = sts.get_caller_identity()['Account'] +# describe all cfn stacks +response = cloudformation.describe_stacks() +myCfnStacks = response['Stacks'] + +class cfnDriftCheck(Auditor): + def execute(self): + for stacks in myCfnStacks: + stackName = str(stacks['StackName']) + stackId = str(stacks['StackId']) + stackArn = 'arn:aws:cloudformation:' + awsRegion + ':' + awsAccountId + ':stack/' + stackName + '/' + stackId + driftCheck = str(stacks['DriftInformation']['StackDriftStatus']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if driftCheck != 'IN_SYNC': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': stackArn + '/cloudformation-drift-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': stackArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[CloudFormation.1] CloudFormation stacks should be monitored for configuration drift', + 'Description': 'CloudFormation stack ' + stackName + ' has not been monitored for drift detection. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'To learn more about drift detection refer to the Detecting Unmanaged Configuration Changes to Stacks and Resources section of the AWS CloudFormation User Guide', + 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudFormationStack', + 'Id': stackArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'stackName': stackName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.MA-1', + 'NIST SP 800-53 MA-2', + 'NIST SP 800-53 MA-3', + 'NIST SP 800-53 MA-5', + 'NIST SP 800-53 MA-6', + 'AICPA TSC CC8.1', + 'ISO 27001:2013 A.11.1.2', + 'ISO 27001:2013 A.11.2.4', + 'ISO 27001:2013 A.11.2.5', + 'ISO 27001:2013 A.11.2.6' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': stackArn + '/cloudformation-drift-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': stackArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudFormation.1] CloudFormation stacks should be monitored for configuration drift', + 'Description': 'CloudFormation stack ' + stackName + ' has been monitored for drift detection.', + 'Remediation': { + 'Recommendation': { + 'Text': 'To learn more about drift detection refer to the Detecting Unmanaged Configuration Changes to Stacks and Resources section of the AWS CloudFormation User Guide', + 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudFormationStack', + 'Id': stackArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'stackName': stackName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.MA-1', + 'NIST SP 800-53 MA-2', + 'NIST SP 800-53 MA-3', + 'NIST SP 800-53 MA-5', + 'NIST SP 800-53 MA-6', + 'AICPA TSC CC8.1', + 'ISO 27001:2013 A.11.1.2', + 'ISO 27001:2013 A.11.2.4', + 'ISO 27001:2013 A.11.2.5', + 'ISO 27001:2013 A.11.2.6' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class cfnMonitoringCheck(Auditor): + def execute(self): + for stacks in myCfnStacks: + stackName = str(stacks['StackName']) + stackId = str(stacks['StackId']) + stackArn = 'arn:aws:cloudformation:' + awsRegion + ':' + awsAccountId + ':stack/' + stackName + '/' + stackId + alertsCheck = str(stacks['NotificationARNs']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if alertsCheck == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': stackArn + '/cloudformation-monitoring-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': stackArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[CloudFormation.2] CloudFormation stacks should be monitored for changes', + 'Description': 'CloudFormation stack ' + stackName + ' does not have monitoring enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your stack should having monitoring enabled refer to the Monitor and Roll Back Stack Operations section of the AWS CloudFormation User Guide', + 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-rollback-triggers.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudFormationStack', + 'Id': stackArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'stackName': stackName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': stackArn + '/cloudformation-monitoring-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': stackArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudFormation.2] CloudFormation stacks should be monitored for changes', + 'Description': 'CloudFormation stack ' + stackName + ' has monitoring enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your stack should having monitoring enabled refer to the Monitor and Roll Back Stack Operations section of the AWS CloudFormation User Guide', + 'Url': 'https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-rollback-triggers.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudFormationStack', + 'Id': stackArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'stackName': stackName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/AWS_CloudTrail_Auditor.py b/eeauditor/auditors/AWS_CloudTrail_Auditor.py new file mode 100644 index 00000000..f7284724 --- /dev/null +++ b/eeauditor/auditors/AWS_CloudTrail_Auditor.py @@ -0,0 +1,597 @@ +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +cloudtrail = boto3.client('cloudtrail') +sts = boto3.client('sts') +# create account id & region variables +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# loop through trails +response = cloudtrail.list_trails() +myCloudTrails = response['Trails'] + +class CloudtrailMultiRegionCheck(Auditor): + def execute(self): + for trails in myCloudTrails: + trailArn = str(trails['TrailARN']) + trailName = str(trails['Name']) + response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + for details in response['trailList']: + multiRegionCheck = str(details['IsMultiRegionTrail']) + if multiRegionCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-multi-region-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[CloudTrail.1] CloudTrail trails should be multi-region', + 'Description': 'CloudTrail trail ' + trailName + ' is not a multi-region trail. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should be multi-region refer to the Receiving CloudTrail Log Files from Multiple Regions section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-multi-region-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudTrail.1] CloudTrail trails should be multi-region', + 'Description': 'CloudTrail trail ' + trailName + ' is a multi-region trail.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should be multi-region refer to the Receiving CloudTrail Log Files from Multiple Regions section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/receive-cloudtrail-log-files-from-multiple-regions.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class CloudtrailCloudwatchLoggingCheck(Auditor): + def execute(self): + for trails in myCloudTrails: + trailArn = str(trails['TrailARN']) + trailName = str(trails['Name']) + response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + for details in response['trailList']: + try: + # this is a passing check + cloudwatchLogCheck = str(details['CloudWatchLogsLogGroupArn']) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-cloudwatch-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudTrail.2] CloudTrail trails should have CloudWatch logging configured', + 'Description': 'CloudTrail trail ' + trailName + ' has CloudWatch Logging configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should send logs to CloudWatch refer to the Monitoring CloudTrail Log Files with Amazon CloudWatch Logs section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/monitor-cloudtrail-log-files-with-cloudwatch-logs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'CloudWatchLogsLogGroupArn'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-cloudwatch-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[CloudTrail.2] CloudTrail trails should have CloudWatch logging configured', + 'Description': 'CloudTrail trail ' + trailName + ' does not have CloudWatch Logging configured. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should send logs to CloudWatch refer to the Monitoring CloudTrail Log Files with Amazon CloudWatch Logs section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/monitor-cloudtrail-log-files-with-cloudwatch-logs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class CloudtrailEncryptionCheck(Auditor): + def execute(self): + for trails in myCloudTrails: + trailArn = str(trails['TrailARN']) + trailName = str(trails['Name']) + response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + for details in response['trailList']: + try: + # this is a passing check + encryptionCheck = str(details['KmsKeyId']) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-kms-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudTrail.3] CloudTrail trails should be encrypted by KMS', + 'Description': 'CloudTrail trail ' + trailName + ' is encrypted by KMS.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should be encrypted with SSE-KMS refer to the Encrypting CloudTrail Log Files with AWS KMS–Managed Keys (SSE-KMS) section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'KmsKeyId'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-kms-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[CloudTrail.3] CloudTrail trails should be encrypted by KMS', + 'Description': 'CloudTrail trail ' + trailName + ' is not encrypted by KMS. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should be encrypted with SSE-KMS refer to the Encrypting CloudTrail Log Files with AWS KMS–Managed Keys (SSE-KMS) section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/encrypting-cloudtrail-log-files-with-aws-kms.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class CloudtrailGlobalServicesCheck(Auditor): + def execute(self): + for trails in myCloudTrails: + trailArn = str(trails['TrailARN']) + trailName = str(trails['Name']) + response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + for details in response['trailList']: + globalServiceEventCheck = str(details['IncludeGlobalServiceEvents']) + if globalServiceEventCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-global-services-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[CloudTrail.4] CloudTrail trails should log management events', + 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should log management events refer to the Management Events section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-events-with-cloudtrail.html#logging-management-events' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-global-services-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudTrail.4] CloudTrail trails should log management events', + 'Description': 'CloudTrail trail ' + trailName + ' logs management events.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should log management events refer to the Management Events section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/logging-management-events-with-cloudtrail.html#logging-management-events' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class CloudtrailLogFileValidationCheck(Auditor): + def execute(self): + for trails in myCloudTrails: + trailArn = str(trails['TrailARN']) + trailName = str(trails['Name']) + response = cloudtrail.describe_trails(trailNameList=[ trailArn ],includeShadowTrails=False) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + for details in response['trailList']: + fileValidationCheck = str(details['LogFileValidationEnabled']) + if fileValidationCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-log-file-validation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[CloudTrail.5] CloudTrail log file validation should be enabled', + 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should have log file validation enabled refer to the Validating CloudTrail Log File Integrity section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-6', + 'NIST SP 800-53 SC-16', + 'NIST SP 800-53 SI-7', + 'AICPA TSC CC7.1', + 'ISO 27001:2013 A.12.2.1', + 'ISO 27001:2013 A.12.5.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3', + 'ISO 27001:2013 A.14.2.4' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': trailArn + '/cloudtrail-log-file-validation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': trailArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[CloudTrail.5] CloudTrail log file validation should be enabled', + 'Description': 'CloudTrail trail ' + trailName + ' does not log management events. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If your trail should have log file validation enabled refer to the Validating CloudTrail Log File Integrity section of the AWS CloudTrail User Guide', + 'Url': 'https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-log-file-validation-intro.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsCloudTrailTrail', + 'Id': trailArn, + 'Partition': 'aws', + 'Region': awsRegion, + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-6', + 'NIST SP 800-53 SC-16', + 'NIST SP 800-53 SI-7', + 'AICPA TSC CC7.1', + 'ISO 27001:2013 A.12.2.1', + 'ISO 27001:2013 A.12.5.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3', + 'ISO 27001:2013 A.14.2.4' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/AWS_CodeBuild_Auditor.py b/eeauditor/auditors/AWS_CodeBuild_Auditor.py new file mode 100644 index 00000000..2af7448e --- /dev/null +++ b/eeauditor/auditors/AWS_CodeBuild_Auditor.py @@ -0,0 +1,775 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +codebuild = boto3.client("codebuild") +# create env vars +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through all CodeBuild projects and list their attributes +response = codebuild.list_projects() +allCodebuildProjects = response["projects"] +if allCodebuildProjects: + response = codebuild.batch_get_projects(names=allCodebuildProjects) + myCodeBuildProjects = response["projects"] +else: + response = "" + myCodeBuildProjects = "" + + +class ArtifactEncryptionCheck(Auditor): + def execute(self): + for projects in myCodeBuildProjects: + buildProjectName = str(projects["name"]) + buildProjectArn = str(projects["arn"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # check if this project supports artifacts + artifactCheck = str(projects["artifacts"]["type"]) + # skip projects without artifacts + if artifactCheck == "NO_ARTIFACTS": + print("No artifacts supported, skipping this check") + pass + else: + # check if encryption for artifacts is disabled + artifactEncryptionCheck = str( + projects["artifacts"]["encryptionDisabled"] + ) + if artifactEncryptionCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/unencrypted-artifacts", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[CodeBuild.1] CodeBuild projects should not have artifact encryption disabled", + "Description": "CodeBuild project " + + buildProjectName + + " has artifact encryption disabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your project should have artifact encryption enabled scroll down to item 8 in the Create a Build Project (Console) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/create-project.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/unencrypted-artifacts", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[CodeBuild.1] CodeBuild projects should not have artifact encryption disabled", + "Description": "CodeBuild project " + + buildProjectName + + " has artifact encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your project should have artifact encryption enabled scroll down to item 8 in the Create a Build Project (Console) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/create-project.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class InsecureSSLCheck(Auditor): + def execute(self): + for projects in myCodeBuildProjects: + buildProjectName = str(projects["name"]) + buildProjectArn = str(projects["arn"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # check if Insecure SSL is enabled for your Source + sourceInsecureSslCheck = str(projects["source"]["insecureSsl"]) + if sourceInsecureSslCheck != "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/insecure-ssl", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[CodeBuild.2] CodeBuild projects should not have insecure SSL configured", + "Description": "CodeBuild project " + + buildProjectName + + " has insecure SSL configured. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have insecure SSL configured refer to the Troubleshooting CodeBuild section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-self-signed-certificate", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/insecure-ssl", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[CodeBuild.2] CodeBuild projects should not have insecure SSL configured", + "Description": "CodeBuild project " + + buildProjectName + + " doesnt have insecure SSL configured.", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have insecure SSL configured refer to the Troubleshooting CodeBuild section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/troubleshooting.html#troubleshooting-self-signed-certificate", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class PlaintextENVvarCheck(Auditor): + def execute(self): + for projects in myCodeBuildProjects: + buildProjectName = str(projects["name"]) + buildProjectArn = str(projects["arn"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # check if this project has any env vars + envVarCheck = str(projects["environment"]["environmentVariables"]) + if envVarCheck == "[]": + print("No env vars, skipping this check") + pass + else: + # loop through env vars + codeBuildEnvVars = projects["environment"]["environmentVariables"] + for envvar in codeBuildEnvVars: + plaintextCheck = str(envvar["type"]) + # identify projects that don't use parameter store or AWS secrets manager + if plaintextCheck == "PLAINTEXT": + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/plaintext-env-vars", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + "Sensitive Data Identifications", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[CodeBuild.3] CodeBuild projects should not have plaintext environment variables", + "Description": "CodeBuild project " + + buildProjectName + + " contains plaintext environment variables. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your project should not contain plaintext environment variables refer to the Buildspec File Name and Storage Location section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": { + "Name": buildProjectName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/plaintext-env-vars", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + "Sensitive Data Identifications", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[CodeBuild.3] CodeBuild projects should not have plaintext environment variables", + "Description": "CodeBuild project " + + buildProjectName + + " does not contain plaintext environment variables.", + "Remediation": { + "Recommendation": { + "Text": "If your project should not contain plaintext environment variables refer to the Buildspec File Name and Storage Location section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#build-spec-ref-syntax", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": { + "Name": buildProjectName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class S3LoggingEncryptionCheck(Auditor): + def execute(self): + for projects in myCodeBuildProjects: + buildProjectName = str(projects["name"]) + buildProjectArn = str(projects["arn"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # check if this project disabled s3 log encryption + s3EncryptionCheck = str( + projects["logsConfig"]["s3Logs"]["encryptionDisabled"] + ) + if s3EncryptionCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/s3-encryption", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[CodeBuild.4] CodeBuild projects should not have S3 log encryption disabled", + "Description": "CodeBuild project " + + buildProjectName + + " has S3 log encryption disabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have S3 log encryption disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/s3-encryption", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[CodeBuild.4] CodeBuild projects should not have S3 log encryption disabled", + "Description": "CodeBuild project " + + buildProjectName + + " has S3 log encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have S3 log encryption disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class CloudwatchLoggingCheck(Auditor): + def execute(self): + for projects in myCodeBuildProjects: + buildProjectName = str(projects["name"]) + buildProjectArn = str(projects["arn"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # check if this project logs to cloudwatch + codeBuildLoggingCheck = str( + projects["logsConfig"]["cloudWatchLogs"]["status"] + ) + if codeBuildLoggingCheck != "ENABLED": + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/cloudwatch-logging", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[CodeBuild.5] CodeBuild projects should have CloudWatch logging enabled", + "Description": "CodeBuild project " + + buildProjectName + + " has CloudWatch logging disabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have CloudWatch logging disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": buildProjectArn + "/cloudwatch-logging", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": buildProjectArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[CodeBuild.5] CodeBuild projects should have CloudWatch logging enabled", + "Description": "CodeBuild project " + + buildProjectName + + " has CloudWatch logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your project should not have CloudWatch logging disabled refer to #20 in the Change a Build Projects Settings (AWS CLI) section of the AWS CodeBuild User Guide", + "Url": "https://docs.aws.amazon.com/codebuild/latest/userguide/change-project.html#change-project-console", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCodeBuildProject", + "Id": buildProjectArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCodeBuildProject": {"Name": buildProjectName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/AWS_DMS_Auditor.py b/eeauditor/auditors/AWS_DMS_Auditor.py new file mode 100644 index 00000000..ade09a3a --- /dev/null +++ b/eeauditor/auditors/AWS_DMS_Auditor.py @@ -0,0 +1,387 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# create boto3 clients +sts = boto3.client('sts') +dms = boto3.client('dms') +# creat env vars +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] + +class dmsReplicationInstancePublicAccessCheck(Auditor): + def execute(self): + # loop through dms replication instances + response = dms.describe_replication_instances() + for repinstances in response['ReplicationInstances']: + dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) + dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) + publicAccessCheck = str(repinstances['PubliclyAccessible']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if publicAccessCheck == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[DMS.1] Database Migration Service instances should not be publicly accessible', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is publicly accessible. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'Public access on DMS instances cannot be changed, however, you can change the subnets that are in the subnet group that is associated with the replication instance to private subnets. For more informaton see the AWS Premium Support post How can I disable public access for an AWS DMS replication instance?.', + 'Url': 'https://aws.amazon.com/premiumsupport/knowledge-center/dms-disable-public-access/' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[DMS.1] Database Migration Service instances should not be publicly accessible', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is not publicly accessible.', + 'Remediation': { + 'Recommendation': { + 'Text': 'Public access on DMS instances cannot be changed, however, you can change the subnets that are in the subnet group that is associated with the replication instance to private subnets. For more informaton see the AWS Premium Support post How can I disable public access for an AWS DMS replication instance?.', + 'Url': 'https://aws.amazon.com/premiumsupport/knowledge-center/dms-disable-public-access/' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class dmsReplicationInstanceMultiAZCheck(Auditor): + def execute(self): + # loop through dms replication instances + response = dms.describe_replication_instances() + for repinstances in response['ReplicationInstances']: + dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) + dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) + mutltiAzCheck = str(repinstances['MultiAZ']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if mutltiAzCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-multi-az-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[DMS.2] Database Migration Service instances should have Multi-AZ configured', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' does not have Multi-AZ configured. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring DMS instances for Multi-AZ refer to the Working with an AWS DMS Replication Instance section of the AWS Database Migration Service User Guide', + 'Url': 'https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-multi-az-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[DMS.2] Database Migration Service instances should have Multi-AZ configured', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' has Multi-AZ configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring DMS instances for Multi-AZ refer to the Working with an AWS DMS Replication Instance section of the AWS Database Migration Service User Guide', + 'Url': 'https://docs.aws.amazon.com/dms/latest/userguide/CHAP_ReplicationInstance.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class dmsReplicationInstanceMinorVersionUpdateCheck(Auditor): + def execute(self): + # loop through dms replication instances + response = dms.describe_replication_instances() + for repinstances in response['ReplicationInstances']: + dmsInstanceId = str(repinstances['ReplicationInstanceIdentifier']) + dmsInstanceArn = str(repinstances['ReplicationInstanceArn']) + minorVersionUpgradeCheck = str(repinstances['AutoMinorVersionUpgrade']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if minorVersionUpgradeCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-minor-version-auto-update-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[DMS.2] Database Migration Service instances should be configured to have minor version updates be automatically applied', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is not configured to have minor version updates be automatically applied. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring DMS instances for minor version updates refer to the AWS DMS Maintenance section of the AWS Database Migration Service User Guide', + 'Url': 'https://docs.amazonaws.cn/en_us/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.Maintenance' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.MA-1', + 'NIST SP 800-53 MA-2', + 'NIST SP 800-53 MA-3', + 'NIST SP 800-53 MA-5', + 'NIST SP 800-53 MA-6', + 'AICPA TSC CC8.1', + 'ISO 27001:2013 A.11.1.2', + 'ISO 27001:2013 A.11.2.4', + 'ISO 27001:2013 A.11.2.5', + 'ISO 27001:2013 A.11.2.6' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': dmsInstanceArn + '/dms-replication-instance-minor-version-auto-update-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': dmsInstanceArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[DMS.2] Database Migration Service instances should be configured to have minor version updates be automatically applied', + 'Description': 'Database Migration Service instance ' + dmsInstanceId + ' is configured to have minor version updates be automatically applied.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on configuring DMS instances for minor version updates refer to the AWS DMS Maintenance section of the AWS Database Migration Service User Guide', + 'Url': 'https://docs.amazonaws.cn/en_us/dms/latest/userguide/CHAP_ReplicationInstance.html#CHAP_ReplicationInstance.Maintenance' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsDmsReplicationInstance', + 'Id': dmsInstanceArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'replicationInstanceId': dmsInstanceId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.MA-1', + 'NIST SP 800-53 MA-2', + 'NIST SP 800-53 MA-3', + 'NIST SP 800-53 MA-5', + 'NIST SP 800-53 MA-6', + 'AICPA TSC CC8.1', + 'ISO 27001:2013 A.11.1.2', + 'ISO 27001:2013 A.11.2.4', + 'ISO 27001:2013 A.11.2.5', + 'ISO 27001:2013 A.11.2.6' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/AWS_Directory_Service_Auditor.py b/eeauditor/auditors/AWS_Directory_Service_Auditor.py new file mode 100644 index 00000000..fe03a608 --- /dev/null +++ b/eeauditor/auditors/AWS_Directory_Service_Auditor.py @@ -0,0 +1,291 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +ds = boto3.client('ds') +sts = boto3.client('sts') +# create account id & region variables +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# loop through Directory Service directories +# not to be confused with weird ass cloud directory +response = ds.describe_directories() +myDirectories = response['DirectoryDescriptions'] + +class DirectoryServiceRadiusCheck(Auditor): + def execute(self): + for directory in myDirectories: + directoryId = str(directory['DirectoryId']) + directoryArn = 'arn:aws:ds:' + awsRegion + ':' + awsAccountId + ':directory/' + directoryId + directoryName = str(directory['Name']) + directoryType = str(directory['Type']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if directoryType != 'SimpleAD': + try: + # this is a passing check + radiusCheck = str(directory['RadiusSettings']) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': directoryArn + '/directory-service-radius-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': directoryArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[DirectoryService.1] Supported directories should have RADIUS enabled for multi-factor authentication (MFA)', + 'Description': 'Directory ' + directoryName + ' has RADIUS enabled and likely supports MFA.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on directory MFA and configuring RADIUS refer to the Multi-factor Authentication Prerequisites section of the AWS Directory Service Administration Guide', + 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started_prereqs.html#prereq_mfa_ad' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': directoryArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'directoryName': directoryName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-6', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 AC-3', + 'NIST SP 800-53 AC-16', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-24', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 PE-2', + 'NIST SP 800-53 PS-3', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.7.1.1', + 'ISO 27001:2013 A.9.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': directoryArn + '/directory-service-radius-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': directoryArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[DirectoryService.1] Supported directories should have RADIUS enabled for multi-factor authentication (MFA)', + 'Description': 'Directory ' + directoryName + ' does not have RADIUS enabled and thus does not support MFA. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on directory MFA and configuring RADIUS refer to the Multi-factor Authentication Prerequisites section of the AWS Directory Service Administration Guide', + 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_getting_started_prereqs.html#prereq_mfa_ad' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': directoryArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'directoryName': directoryName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-6', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 AC-3', + 'NIST SP 800-53 AC-16', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-24', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 PE-2', + 'NIST SP 800-53 PS-3', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.7.1.1', + 'ISO 27001:2013 A.9.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print('SimpleAD does not support RADIUS, skipping') + pass + +class DirectoryServiceCloudwatchLogsCheck(Auditor): + def execute(self): + for directory in myDirectories: + directoryId = str(directory['DirectoryId']) + directoryArn = 'arn:aws:ds:' + awsRegion + ':' + awsAccountId + ':directory/' + directoryId + directoryName = str(directory['Name']) + response = ds.list_log_subscriptions(DirectoryId=directoryId) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(response['LogSubscriptions']) == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': directoryArn + '/directory-service-cloudwatch-logs-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': directoryArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[DirectoryService.2] Directories should have log forwarding enabled', + 'Description': 'Directory ' + directoryName + ' does not have log forwarding enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on directory log forwarding to CloudWatch Logs refer to the Enable Log Forwarding section of the AWS Directory Service Administration Guide', + 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_enable_log_forwarding.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': directoryArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'directoryName': directoryName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': directoryArn + '/directory-service-cloudwatch-logs-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': directoryArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[DirectoryService.2] Directories should have log forwarding enabled', + 'Description': 'Directory ' + directoryName + ' does not have log forwarding enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on directory log forwarding to CloudWatch Logs refer to the Enable Log Forwarding section of the AWS Directory Service Administration Guide', + 'Url': 'https://docs.aws.amazon.com/directoryservice/latest/admin-guide/ms_ad_enable_log_forwarding.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': directoryArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'directoryName': directoryName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/AWS_Glue_Auditor.py b/eeauditor/auditors/AWS_Glue_Auditor.py new file mode 100644 index 00000000..37248827 --- /dev/null +++ b/eeauditor/auditors/AWS_Glue_Auditor.py @@ -0,0 +1,814 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +glue = boto3.client('glue') +# create account id & region variables +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# loop through Glue Crawlers +try: + response = glue.list_crawlers() + myCrawlers = response['CrawlerNames'] +except Exception as e: + print(e) + +class CrawlerS3EncryptionCheck(Auditor): + def execute(self): + for crawlers in myCrawlers: + crawlerName = str(crawlers) + crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_crawler(Name=crawlerName) + crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) + try: + response = glue.get_security_configuration(Name=crawlerSecConfig) + s3EncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['S3Encryption'][0]['S3EncryptionMode']) + if s3EncryptionCheck == 'DISABLED': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-s3-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Glue.1] AWS Glue crawler security configurations should enable Amazon S3 encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables S3 encryption. When you are writing Amazon S3 data, you use either server-side encryption with Amazon S3 managed keys (SSE-S3) or server-side encryption with AWS KMS managed keys (SSE-KMS). Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-s3-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.1] AWS Glue crawler security configurations should enable Amazon S3 encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables S3 encryption.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + +class CrawlerCloudwatchEncryptionCheck(Auditor): + def execute(self): + for crawlers in myCrawlers: + crawlerName = str(crawlers) + crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_crawler(Name=crawlerName) + crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) + try: + response = glue.get_security_configuration(Name=crawlerSecConfig) + cwEncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['CloudWatchEncryption']['CloudWatchEncryptionMode']) + if cwEncryptionCheck == 'DISABLED': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-cloudwatch-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Glue.2] AWS Glue crawler security configurations should enable Amazon CloudWatch Logs encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables CloudWatch Logs encryption. Server-side (SSE-KMS) encryption is used to encrypt CloudWatch Logs. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-cloudwatch-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.2] AWS Glue crawler security configurations should enable Amazon CloudWatch Logs encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables CloudWatch Logs encryption.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + +class CrawlerJobBookmarkEncryptionCheck(Auditor): + def execute(self): + for crawlers in myCrawlers: + crawlerName = str(crawlers) + crawlerArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':crawler/' + crawlerName + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_crawler(Name=crawlerName) + crawlerSecConfig = str(response['Crawler']['CrawlerSecurityConfiguration']) + try: + response = glue.get_security_configuration(Name=crawlerSecConfig) + jobBookmarkEncryptionCheck = str(response['SecurityConfiguration']['EncryptionConfiguration']['JobBookmarksEncryption']['JobBookmarksEncryptionMode']) + if jobBookmarkEncryptionCheck == 'DISABLED': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-job-bookmark-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Glue.3] AWS Glue crawler security configurations should enable job bookmark encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' does not have a security configuration that enables job bookmark encryption. Client-side (CSE-KMS) encryption is used to encrypt job bookmarks, bookmark data is encrypted before it is sent to Amazon S3 for storage. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': crawlerArn + '/glue-crawler-job-bookmark-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': crawlerArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.3] AWS Glue crawler security configurations should enable job bookmark encryption', + 'Description': 'AWS Glue crawler ' + crawlerName + ' has a security configuration that enables job bookmark encryption.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on encryption and AWS Glue security configurations refer to the Working with Security Configurations on the AWS Glue Console section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/console-security-configurations.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueCrawler', + 'Id': crawlerArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'crawlerName': crawlerName, + 'securityConfigurationId': crawlerSecConfig + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + +class GlueDataCatalogEncryptionCheck(Auditor): + def execute(self): + catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_data_catalog_encryption_settings() + catalogEncryptionCheck = str(response['DataCatalogEncryptionSettings']['EncryptionAtRest']['CatalogEncryptionMode']) + if catalogEncryptionCheck == 'DISABLED': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Glue.4] AWS Glue data catalogs should be encrypted at rest', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is not encrypted. You can enable or disable encryption settings for the entire Data Catalog. In the process, you specify an AWS KMS key that is automatically used when objects, such as tables, databases, partitions, table versions, connections and/or user-defined functions, are written to the Data Catalog. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog encryption refer to the Encrypting Your Data Catalog section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.4] AWS Glue data catalogs should be encrypted at rest', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is encrypted.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog encryption refer to the Encrypting Your Data Catalog section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-glue-data-catalog.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class GlueDataCatalogPasswordEncryptionCheck(Auditor): + def execute(self): + catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_data_catalog_encryption_settings() + passwordEncryptionCheck = str(response['DataCatalogEncryptionSettings']['ConnectionPasswordEncryption']['ReturnConnectionPasswordEncrypted']) + if passwordEncryptionCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-password-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Glue.5] AWS Glue data catalogs should be configured to encrypt connection passwords', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is not configured to encrypt connection passwords. You can retrieve connection passwords in the AWS Glue Data Catalog by using the GetConnection and GetConnections API operations. These passwords are stored in the Data Catalog connection and are used when AWS Glue connects to a Java Database Connectivity (JDBC) data store. When the connection was created or updated, an option in the Data Catalog settings determined whether the password was encrypted. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog connection password encryption refer to the Encrypting Connection Passwords section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-connection-passwords.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-password-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.5] AWS Glue data catalogs should be configured to encrypt connection passwords', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' is configured to encrypt connection passwords.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog connection password encryption refer to the Encrypting Connection Passwords section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/encrypt-connection-passwords.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class GlueDataCatalogResourcePolicyCheck(Auditor): + def execute(self): + catalogArn = 'arn:aws:glue:' + awsRegion + ':' + awsAccountId + ':catalog' + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = glue.get_resource_policy() + policyHash = str(response['PolicyHash']) + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-resource-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Glue.6] AWS Glue data catalogs should enforce fine-grained access controls with a resource policy', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' uses a resource policy.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog resource policies refer to the AWS Glue Resource Policies for Access Control section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'policyHash': policyHash + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == 'An error occurred (EntityNotFoundException) when calling the GetResourcePolicy operation: Policy not found': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': catalogArn + '/glue-data-catalog-resource-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': catalogArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Glue.6] AWS Glue data catalogs should enforce fine-grained access controls with a resource policy', + 'Description': 'The AWS Glue data catalog for account ' + awsAccountId + ' does not use a resource policy. AWS Glue supports using resource policies to control access to Data Catalog resources. These resources include databases, tables, connections, and user-defined functions, along with the Data Catalog APIs that interact with these resources. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on data catalog resource policies refer to the AWS Glue Resource Policies for Access Control section of the AWS Glue Developer Guide', + 'Url': 'https://docs.aws.amazon.com/glue/latest/dg/glue-resource-policies.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsGlueDataCatalog', + 'Id': catalogArn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) diff --git a/eeauditor/auditors/AWS_IAM_Auditor.py b/eeauditor/auditors/AWS_IAM_Auditor.py new file mode 100644 index 00000000..60f14f0b --- /dev/null +++ b/eeauditor/auditors/AWS_IAM_Auditor.py @@ -0,0 +1,1106 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +iam = boto3.client('iam') +# create account id & region variables +awsAccount = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +# loop through IAM users +try: + response = iam.list_users(MaxItems=1000) + allUsers = response['Users'] +except Exception as e: + print(e) + +class iamAccessKeyAgeCheck(Auditor): + def execute(self): + for users in allUsers: + userName = str(users['UserName']) + userArn = str(users['Arn']) + try: + response = iam.list_access_keys(UserName=userName) + for keys in response['AccessKeyMetadata']: + keyUserName = str(keys['UserName']) + keyId = str(keys['AccessKeyId']) + keyStatus = str(keys['Status']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if keyStatus == 'Active': + keyCreateDate = keys['CreateDate'] + todaysDatetime = datetime.datetime.now(datetime.timezone.utc) + keyAgeFinder = todaysDatetime - keyCreateDate + if keyAgeFinder <= datetime.timedelta(days=90): + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': keyUserName + keyId + '/iam-access-key-age-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn + keyId, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.1] IAM Access Keys should be rotated every 90 days', + 'Description': 'IAM access key ' + keyId + ' for user ' + keyUserName + ' is not over 90 days old.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on IAM access key rotation refer to the Rotating Access Keys section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_RotateAccessKey' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamAccessKey', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsIamAccessKey': { + 'PrincipalId': keyId, + 'PrincipalName': keyUserName, + 'Status': keyStatus + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': keyUserName + keyId + '/iam-access-key-age-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn + keyId, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[IAM.1] IAM Access Keys should be rotated every 90 days', + 'Description': 'IAM access key ' + keyId + ' for user ' + keyUserName + ' is over 90 days old. As a security best practice, AWS recommends that you regularly rotate (change) IAM user access keys. If your administrator granted you the necessary permissions, you can rotate your own access keys. Refer to the remediation section to remediate this behavior.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on IAM access key rotation refer to the Rotating Access Keys section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_RotateAccessKey' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamAccessKey', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'AwsIamAccessKey': { + 'PrincipalId': keyId, + 'PrincipalName': keyUserName, + 'Status': keyStatus + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + pass + except Exception as e: + print(e) + +class UserPermissionsBoundaryCheck(Auditor): + def execute(self): + for users in allUsers: + userName = str(users['UserName']) + userArn = str(users['Arn']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + permBoundaryArn = str(users['PermissionsBoundary']['PermissionsBoundaryArn']) + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-permissions-boundary-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.2] IAM users should have permissions boundaries attached', + 'Description': 'IAM user ' + userName + ' has a permissions boundary attached.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on permissions boundaries refer to the Permissions Boundaries for IAM Entities section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName, + 'permissionsBoundaryArn': permBoundaryArn + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-4', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 AC-3', + 'NIST SP 800-53 AC-5', + 'NIST SP 800-53 AC-6', + 'NIST SP 800-53 AC-14', + 'NIST SP 800-53 AC-16', + 'NIST SP 800-53 AC-24', + 'AICPA TSC CC6.3', + 'ISO 27001:2013 A.6.1.2', + 'ISO 27001:2013 A.9.1.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.4.1', + 'ISO 27001:2013 A.9.4.4', + 'ISO 27001:2013 A.9.4.5' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'PermissionsBoundary'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-permissions-boundary-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[IAM.2] IAM users should have permissions boundaries attached', + 'Description': 'IAM user ' + userName + ' does not have a permissions boundary attached. A permissions boundary is an advanced feature for using a managed policy to set the maximum permissions that an identity-based policy can grant to an IAM entity. A permissions boundary allows it to perform only the actions that are allowed by both its identity-based policies and its permissions boundaries. Refer to the remediation section to remediate this behavior.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on permissions boundaries refer to the Permissions Boundaries for IAM Entities section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_boundaries.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-4', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 AC-3', + 'NIST SP 800-53 AC-5', + 'NIST SP 800-53 AC-6', + 'NIST SP 800-53 AC-14', + 'NIST SP 800-53 AC-16', + 'NIST SP 800-53 AC-24', + 'AICPA TSC CC6.3', + 'ISO 27001:2013 A.6.1.2', + 'ISO 27001:2013 A.9.1.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.4.1', + 'ISO 27001:2013 A.9.4.4', + 'ISO 27001:2013 A.9.4.5' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class UserMfaCheck(Auditor): + def execute(self): + for users in allUsers: + userName = str(users['UserName']) + userArn = str(users['Arn']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = iam.list_mfa_devices(UserName=userName) + if str(response['MFADevices']) == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-mfa-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[IAM.3] IAM users should have Multi-Factor Authentication (MFA) enabled', + 'Description': 'IAM user ' + userName + ' does not have MFA enabled. For increased security, AWS recommends that you configure multi-factor authentication (MFA) to help protect your AWS resources. Refer to the remediation section to remediate this behavior.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on MFA refer to the Using Multi-Factor Authentication (MFA) in AWS section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-mfa-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.3] IAM users should have Multi-Factor Authentication (MFA) enabled', + 'Description': 'IAM user ' + userName + ' has MFA enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on MFA refer to the Using Multi-Factor Authentication (MFA) in AWS section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_mfa.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class UserInlinePolicyCheck(Auditor): + def execute(self): + for users in allUsers: + userName = str(users['UserName']) + userArn = str(users['Arn']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = iam.list_user_policies(UserName=userName) + if str(response['PolicyNames']) != '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-attach-inline-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[IAM.4] IAM users should not have attached in-line policies', + 'Description': 'IAM user ' + userName + ' has an in-line policy attached. It is recommended that IAM policies be applied directly to groups and roles but not users. Refer to the remediation section to remediate this behavior.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-attach-inline-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.4] IAM users should not have attached in-line policies', + 'Description': 'IAM user ' + userName + ' does not have an in-line policy attached.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class UserDirectAttachedPolicyCheck(Auditor): + def execute(self): + for users in allUsers: + userName = str(users['UserName']) + userArn = str(users['Arn']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = iam.list_attached_user_policies(UserName=userName) + if str(response['AttachedPolicies']) != '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-attach-managed-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[IAM.5] IAM users should not have attached managed policies', + 'Description': 'IAM user ' + userName + ' has a managed policy attached. It is recommended that IAM policies be applied directly to groups and roles but not users. Refer to the remediation section to remediate this behavior.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': userArn + '/iam-user-attach-managed-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': userArn, + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.5] IAM users should not have attached managed policies', + 'Description': 'IAM user ' + userName + ' does not have a managed policy attached.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on user attached policies refer to the Managed Policies and Inline Policies section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsIamUser', + 'Id': userArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'PrincipalName': userName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + +class CISawsFoundationsBenchmarkPWpolicyCheck(Auditor): + def execute(self): + try: + response = iam.get_account_password_policy() + pwPolicy = response['PasswordPolicy'] + minPwLength = int(pwPolicy['MinimumPasswordLength']) + symbolReq = str(pwPolicy['RequireSymbols']) + numberReq = str(pwPolicy['RequireNumbers']) + uppercaseReq = str(pwPolicy['RequireUppercaseCharacters']) + lowercaseReq = str(pwPolicy['RequireLowercaseCharacters']) + maxPwAge = int(pwPolicy['MaxPasswordAge']) + pwReuse = int(pwPolicy['PasswordReusePrevention']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if minPwLength >= 14 and maxPwAge <= 90 and pwReuse >= 24 and symbolReq == 'True' and numberReq == 'True' and uppercaseReq =='True' and lowercaseReq == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccount + '/cis-aws-foundations-benchmark-pw-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': awsAccount + 'iam-password-policy', + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.6] The IAM password policy should meet or exceed the AWS CIS Foundations Benchmark standard', + 'Description': 'The IAM password policy for account ' + awsAccount + ' meets or exceeds the AWS CIS Foundations Benchmark standard.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on the CIS AWS Foundations Benchmark standard for the password policy refer to the linked Standard', + 'Url': 'https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccount, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccount + '/cis-aws-foundations-benchmark-pw-policy-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': awsAccount + 'iam-password-policy', + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[IAM.6] The IAM password policy should meet or exceed the AWS CIS Foundations Benchmark standard', + 'Description': 'The IAM password policy for account ' + awsAccount + ' does not meet the AWS CIS Foundations Benchmark standard. Refer to the remediation instructions if this configuration is not intended.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on the CIS AWS Foundations Benchmark standard for the password policy refer to the linked Standard', + 'Url': 'https://d1.awsstatic.com/whitepapers/compliance/AWS_CIS_Foundations_Benchmark.pdf' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccount, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + except Exception as e: + print(e) + +class ServerCertsCheck(Auditor): + def execute(self): + try: + response = iam.list_server_certificates() + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(response['ServerCertificateMetadataList']) != '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccount + '/server-x509-certs-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': awsAccount + 'server-cert', + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[IAM.7] There should not be any server certificates stored in AWS IAM', + 'Description': 'There are server certificates stored in AWS IAM for the account ' + awsAccount + '. ACM is the preferred tool to provision, manage, and deploy your server certificates. With ACM you can request a certificate or deploy an existing ACM or external certificate to AWS resources. Certificates provided by ACM are free and automatically renew. Refer to the remediation instructions if this configuration is not intended.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on server certificates refer to the Working with Server Certificates section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccount, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccount + '/server-x509-certs-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccount + ':product/' + awsAccount + '/default', + 'GeneratorId': awsAccount + 'server-cert', + 'AwsAccountId': awsAccount, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[IAM.7] There should not be any server certificates stored in AWS IAM', + 'Description': 'There are not server certificates stored in AWS IAM for the account ' + awsAccount + '.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on server certificates refer to the Working with Server Certificates section of the AWS IAM User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_server-certs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccount, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/AWS_License_Manager_Auditor.py b/eeauditor/auditors/AWS_License_Manager_Auditor.py new file mode 100644 index 00000000..b6c693a8 --- /dev/null +++ b/eeauditor/auditors/AWS_License_Manager_Auditor.py @@ -0,0 +1,162 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +licensemanager = boto3.client('license-manager') +# create account id & region variables +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] + +class LicenseManagerHardCountCheck(Auditor): + def execute(self): + try: + response = licensemanager.list_license_configurations() + lmCheck = str(response['LicenseConfigurations']) + if lmCheck == '[]': + pass + else: + myLiscMgrConfigs = response['LicenseConfigurations'] + for lmconfigs in myLiscMgrConfigs: + liscConfigArn = str(lmconfigs['LicenseConfigurationArn']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = licensemanager.get_license_configuration(LicenseConfigurationArn=liscConfigArn) + liscConfigId = str(response['LicenseConfigurationId']) + liscConfigName = str(response['Name']) + hardLimitCheck = str(response['LicenseCountHardLimit']) + if hardLimitCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': liscConfigArn + '/license-manager-enforce-hard-limit-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': liscConfigArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[LicenseManager.1] License Manager license configurations should be configured to enforce a hard limit', + 'Description': 'License Manager license configuration ' + liscConfigName + ' does not enforce a hard limit. Enforcing a hard limit prevents new instances from being created that if you have already provisioned all available licenses. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on hard limits refer to the License Configuration Parameters and Rules section of the AWS License Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/license-manager/latest/userguide/config-overview.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': liscConfigArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'licenseConfigurationId': liscConfigId, + 'licenseConfigurationName': liscConfigName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.AM-2', + 'NIST SP 800-53 CM-8', + 'NIST SP 800-53 PM-5', + 'AICPA TSC CC3.2', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.1.1', + 'ISO 27001:2013 A.8.1.2', + 'ISO 27001:2013 A.12.5.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': liscConfigArn + '/license-manager-enforce-hard-limit-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': liscConfigArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[LicenseManager.1] License Manager license configurations should be configured to enforce a hard limit', + 'Description': 'License Manager license configuration ' + liscConfigName + ' enforces a hard limit.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For information on hard limits refer to the License Configuration Parameters and Rules section of the AWS License Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/license-manager/latest/userguide/config-overview.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': liscConfigArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'licenseConfigurationId': liscConfigId, + 'licenseConfigurationName': liscConfigName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.AM-2', + 'NIST SP 800-53 CM-8', + 'NIST SP 800-53 PM-5', + 'AICPA TSC CC3.2', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.1.1', + 'ISO 27001:2013 A.8.1.2', + 'ISO 27001:2013 A.12.5.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) diff --git a/eeauditor/auditors/AWS_Secrets_Manager_Auditor.py b/eeauditor/auditors/AWS_Secrets_Manager_Auditor.py new file mode 100644 index 00000000..a5d4e3c3 --- /dev/null +++ b/eeauditor/auditors/AWS_Secrets_Manager_Auditor.py @@ -0,0 +1,329 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +secretsmanager = boto3.client('secretsmanager') +# create env vars +awsRegion = os.environ['AWS_REGION'] +awsAccountId = sts.get_caller_identity()['Account'] +# loop through all secrets +response = secretsmanager.list_secrets(MaxResults=100) +myAsmSecrets = response['SecretList'] + +class SecretAgeCheck(Auditor): + def execute(self): + for secrets in myAsmSecrets: + secretArn = str(secrets['ARN']) + secretName = str(secrets['Name']) + lastChangedDate = (secrets['LastChangedDate']) + todaysDatetime = datetime.datetime.now(datetime.timezone.utc) + secretAgeFinder = todaysDatetime - lastChangedDate + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if secretAgeFinder >= datetime.timedelta(days=90): + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': secretArn + '/secrets-manager-age-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': secretArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SecretsManager.1] Secrets over 90 days old should be rotated', + 'Description': secretName + ' is over 90 days old and should be rotated. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': secretArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'secretName': secretName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': secretArn + '/secrets-manager-age-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': secretArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SecretsManager.1] Secrets over 90 days old should be rotated', + 'Description': secretName + ' is over 90 days old and should be rotated.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': secretArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'secretName': secretName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class SecretChangedInLast90Check(Auditor): + def execute(self): + for secrets in myAsmSecrets: + secretArn = str(secrets['ARN']) + secretName = str(secrets['Name']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + rotationCheck = str(secrets['RotationEnabled']) + print(rotationCheck) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': secretArn + '/secrets-manager-rotation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': secretArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SecretsManager.2] Secrets should have automatic rotation configured', + 'Description': secretName + ' has automatic rotation configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': secretArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'secretName': secretName } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': secretArn + '/secrets-manager-rotation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': secretArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SecretsManager.2] Secrets should have automatic rotation configured', + 'Description': secretName + ' does not have automatic rotation configured. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Secret Rotation refer to the Rotating Your AWS Secrets Manager Secrets section of the AWS Secrets Manager User Guide', + 'Url': 'https://docs.aws.amazon.com/secretsmanager/latest/userguide/rotating-secrets.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': secretArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'secretName': secretName } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-1', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-2', + 'NIST SP 800-53 IA-1', + 'NIST SP 800-53 IA-2', + 'NIST SP 800-53 IA-3', + 'NIST SP 800-53 IA-4', + 'NIST SP 800-53 IA-5', + 'NIST SP 800-53 IA-6', + 'NIST SP 800-53 IA-7', + 'NIST SP 800-53 IA-8', + 'NIST SP 800-53 IA-9', + 'NIST SP 800-53 IA-10', + 'NIST SP 800-53 IA-11', + 'AICPA TSC CC6.1', + 'AICPA TSC CC6.2', + 'ISO 27001:2013 A.9.2.1', + 'ISO 27001:2013 A.9.2.2', + 'ISO 27001:2013 A.9.2.3', + 'ISO 27001:2013 A.9.2.4', + 'ISO 27001:2013 A.9.2.6', + 'ISO 27001:2013 A.9.3.1', + 'ISO 27001:2013 A.9.4.2', + 'ISO 27001:2013 A.9.4.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding diff --git a/eeauditor/auditors/AWS_Security_Hub_Auditor.py b/eeauditor/auditors/AWS_Security_Hub_Auditor.py new file mode 100644 index 00000000..1be88fac --- /dev/null +++ b/eeauditor/auditors/AWS_Security_Hub_Auditor.py @@ -0,0 +1,170 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# import boto3 clients +securityhub = boto3.client('securityhub') +sts = boto3.client('sts') +# create aws account ID variable for filters +awsAccountId = sts.get_caller_identity()['Account'] +awsRegion = os.environ['AWS_REGION'] +try: + # look for active high or critical findings from AWS products + getFindings = securityhub.get_findings( + Filters={ + # look for findings that belong to current account + # will help deconflict checks run in a master account + 'AwsAccountId': [ + { + 'Value': awsAccountId, + 'Comparison': 'EQUALS' + } + ], + # look for high or critical severity findings + 'SeverityLabel': [ + { + 'Value': 'HIGH', + 'Comparison': 'EQUALS' + }, + { + 'Value': 'CRITICAL', + 'Comparison': 'EQUALS' + } + ], + # look for AWS security hub integrations + # company can be AWS or Amazon depending on service + 'CompanyName': [ + { + 'Value': 'AWS', + 'Comparison': 'EQUALS' + }, + { + 'Value': 'Amazon', + 'Comparison': 'EQUALS' + } + ], + # check for Active Records + 'RecordState': [ + { + 'Value': 'ACTIVE', + 'Comparison': 'EQUALS' + } + ] + }, + SortCriteria=[ + { + 'Field': 'SeverityLabel', + 'SortOrder': 'asc' + } + ], + MaxResults=100 + ) +except Exception as e: + print(e) + +class HighCriticalFindings(Auditor): + def execute(self): + generatorId = str(getFindings['ResponseMetadata']['RequestId']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(getFindings['Findings']) == '[]': + finding={ + 'SchemaVersion': '2018-10-08', + 'Id': 'high-critical-findings-located/' + awsAccountId, + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorId, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Title': '[SecurityHub.1] Security Hub should not have active high or critical severity findings from AWS services', + 'Description': 'High or critical findings were not found in the Security Hub hub for AWS account ' + awsAccountId, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': 'high-critical-findings-located/' + awsAccountId, + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorId, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { + 'Label': 'CRITICAL' + }, + 'Title': '[SecurityHub.1] Security Hub should not have active high or critical severity findings from AWS services', + 'Description': 'High or critical findings were found in the Security Hub hub for AWS account ' + awsAccountId, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding diff --git a/eeauditor/auditors/AWS_Security_Services_Auditor.py b/eeauditor/auditors/AWS_Security_Services_Auditor.py new file mode 100644 index 00000000..d3143ad0 --- /dev/null +++ b/eeauditor/auditors/AWS_Security_Services_Auditor.py @@ -0,0 +1,369 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import uuid +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +accessanalyzer = boto3.client('accessanalyzer') +guardduty = boto3.client('guardduty') +detective = boto3.client('detective') +# create env vars +awsRegion = os.environ['AWS_REGION'] +awsAccountId = sts.get_caller_identity()['Account'] + +class iamAccessAnalyzerDetectorCheck(Auditor): + def execute(self): + response = accessanalyzer.list_analyzers() + iamAccessAnalyzerCheck = str(response['analyzers']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + # unique ID + generatorUuid = str(uuid.uuid4()) + if iamAccessAnalyzerCheck == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-iaa-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SecSvcs.1] Amazon IAM Access Analyzer should be enabled', + 'Description': 'Amazon IAM Access Analyzer is not enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If IAM Access Analyzer should be enabled refer to the Enabling Access Analyzer section of the AWS Identity and Access Management User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html#access-analyzer-enabling' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-iaa-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SecSvcs.1] Amazon IAM Access Analyzer should be enabled', + 'Description': 'Amazon IAM Access Analyzer is enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If IAM Access Analyzer should be enabled refer to the Enabling Access Analyzer section of the AWS Identity and Access Management User Guide', + 'Url': 'https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-getting-started.html#access-analyzer-enabling' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class GuardDutyDetectorCheck(Auditor): + def execute(self): + response = guardduty.list_detectors() + guarddutyDetectorCheck = str(response['DetectorIds']) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + # unique ID + generatorUuid = str(uuid.uuid4()) + if guarddutyDetectorCheck == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-guardduty-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SecSvcs.2] Amazon GuardDuty should be enabled', + 'Description': 'Amazon GuardDuty is not enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If GuardDuty should be enabled refer to the Setting Up GuardDuty section of the Amazon GuardDuty User Guide', + 'Url': 'https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-guardduty-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SecSvcs.2] Amazon GuardDuty should be enabled', + 'Description': 'Amazon GuardDuty is not enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If GuardDuty should be enabled refer to the Setting Up GuardDuty section of the Amazon GuardDuty User Guide', + 'Url': 'https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_settingup.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class DetectiveGraphCheck(Auditor): + def execute(self): + try: + response = detective.list_graphs(MaxResults=200) + # ISO Time + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + # unique ID + generatorUuid = str(uuid.uuid4()) + if str(response['GraphList']) == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-detective-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SecSvcs.3] Amazon Detective should be enabled', + 'Description': 'Amazon Detective is not enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'If Detective should be enabled refer to the Setting up Amazon Detective section of the Amazon Detective Administration Guide', + 'Url': 'https://docs.aws.amazon.com/detective/latest/adminguide/detective-setup.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/security-services-detective-enabled-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': generatorUuid, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SecSvcs.3] Amazon Detective should be enabled', + 'Description': 'Amazon Detective is enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'If Detective should be enabled refer to the Setting up Amazon Detective section of the Amazon Detective Administration Guide', + 'Url': 'https://docs.aws.amazon.com/detective/latest/adminguide/detective-setup.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-2', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 SI-4', + 'AICPA TSC 7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.1', + 'ISO 27001:2013 A.16.1.4' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_AppStream_Auditor.py b/eeauditor/auditors/Amazon_AppStream_Auditor.py new file mode 100644 index 00000000..9af82f96 --- /dev/null +++ b/eeauditor/auditors/Amazon_AppStream_Auditor.py @@ -0,0 +1,542 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +appstream = boto3.client("appstream") +sts = boto3.client("sts") +# create account id & region variables +awsAccount = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] + + +class DefaultInternetAccessCheck(Auditor): + def execute(self): + # loop through AppStream 2.0 fleets + response = appstream.describe_fleets() + myAppstreamFleets = response["Fleets"] + for fleet in myAppstreamFleets: + iso8601Time = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + fleetArn = str(fleet["Arn"]) + fleetName = str(fleet["DisplayName"]) + # find fleets that are configured to provide default internet access + defaultInternetAccessCheck = str(fleet["EnableDefaultInternetAccess"]) + if defaultInternetAccessCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": fleetArn + "/appstream-default-internet-access", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": fleetArn, + "AwsAccountId": awsAccount, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[AppStream.1] AppStream 2.0 fleets should not provide default internet access", + "Description": "AppStream 2.0 fleet " + + fleetName + + " is configured to provide default internet access. If you use the Default Internet Access option for enabling internet access, the NAT configuration is not limited to 100 fleet instances. If your deployment must support more than 100 concurrent users, use this configuration. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your fleet should not have default internet access refer to the instructions in the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/internet-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAppStreamFleet", + "Id": fleetArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"fleetName": fleetName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": fleetArn + "/appstream-default-internet-access", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": fleetArn, + "AwsAccountId": awsAccount, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AppStream.1] AppStream 2.0 fleets should not provide default internet access", + "Description": "AppStream 2.0 fleet " + + fleetName + + " is not configured to provide default internet access.", + "Remediation": { + "Recommendation": { + "Text": "If your fleet should not have default internet access refer to the instructions in the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/internet-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAppStreamFleet", + "Id": fleetArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"fleetName": fleetName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class PublicImageCheck(Auditor): + """Check for appstream images marked public + + TODO: Right now, this check is returning all public images including what appear + to be globally public images. My best guess right now is that we could look at + the arn of public images that don't have an accountId in the arn and ignore those. + """ + + def execute(self): + # loop through AppStream 2.0 images + response = appstream.describe_images(Type="PUBLIC", MaxResults=25) + myAppstreamImages = response["Images"] + for images in myAppstreamImages: + imageName = str(images["Name"]) + imageArn = str(images["Arn"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": imageArn + "/appstream-public-image", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": imageArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[AppStream.2] AppStream 2.0 images you build should not be publicly accessible", + "Description": "AppStream 2.0 image " + + imageName + + " is publicly accessible. Permissions set on images that are shared with you may limit what you can do with those images. Refer to the remediation instructions if this configuration is not intended. Note that AWS managed AppStream 2.0 images will always be publicly accessible", + "Remediation": { + "Recommendation": { + "Text": "If your image should not be publicly accessible refer to the instructions in the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/administer-images.html#stop-sharing-image-with-all-accounts", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": imageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"Image Name": imageName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class CompromiseAppstreamUserCheck(Auditor): + def execute(self): + # loop through AppStream 2.0 users + response = appstream.describe_users(AuthenticationType="USERPOOL") + myAppStreamUsers = response["Users"] + for users in myAppStreamUsers: + userArn = str(users["Arn"]) + userName = str(users["UserName"]) + userStatus = str(users["Status"]) + iso8601Time = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + if userStatus == "COMPROMISED": + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": userArn + "/appstream-compromised-user", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Unusual Behaviors/User", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[AppStream.3] AppStream 2.0 users should be monitored for signs of compromise", + "Description": "AppStream 2.0 user " + + userName + + " is compromised. COMPROMISED – The user is disabled because of a potential security threat. Refer to the remediation instructions for information on how to remove them", + "Remediation": { + "Recommendation": { + "Text": "To disable and remove compromised users refer to the instructions in the User Pool Administration section of the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/user-pool-admin.html#user-pool-admin-disabling", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": userArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"userName": userName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-3", + "NIST CSF DE.CM-7", + "NIST SP 800-53 AU-12", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 CM-3", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PE-3", + "NIST SP 800-53 PE-6", + "NIST SP 800-53 PE-20", + "NIST SP 800-53 PM-12", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 RA-3", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5" "AICPA TSC CC3.2", + "AICPA TSC CC7.2", + "ISO 27001:2013 Clause 6.1.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.14.2.7", + "ISO 27001:2013 A.15.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": userArn + "/appstream-compromised-user", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Unusual Behaviors/User", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AppStream.3] AppStream 2.0 users should be monitored for signs of compromise", + "Description": "AppStream 2.0 user " + userName + " is not compromised.", + "Remediation": { + "Recommendation": { + "Text": "To disable and remove compromised users refer to the instructions in the User Pool Administration section of the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/user-pool-admin.html#user-pool-admin-disabling", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": userArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"userName": userName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-3", + "NIST CSF DE.CM-7", + "NIST SP 800-53 AU-12", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 CM-3", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PE-3", + "NIST SP 800-53 PE-6", + "NIST SP 800-53 PE-20", + "NIST SP 800-53 PM-12", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 RA-3", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5" "AICPA TSC CC3.2", + "AICPA TSC CC7.2", + "ISO 27001:2013 Clause 6.1.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.14.2.7", + "ISO 27001:2013 A.15.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class UserpoolAuthCheck(Auditor): + def execute(self): + # loop through AppStream 2.0 users + response = appstream.describe_users(AuthenticationType="USERPOOL") + myAppStreamUsers = response["Users"] + for users in myAppStreamUsers: + iso8601Time = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + userArn = str(users["Arn"]) + userName = str(users["UserName"]) + # find users that do not auth with SAML + # basic auth & API access will show as non-compliant + userAuthType = str(users["AuthenticationType"]) + if userAuthType != "SAML": + finding = { + "SchemaVersion": "2018-10-08", + "Id": userArn + "/appstream-compromised-user", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userArn, + "AwsAccountId": awsAccount, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[AppStream.4] AppStream 2.0 users should be configured to authenticate using SAML", + "Description": "AppStream 2.0 user " + + userName + + " is not configured to authenticate using SAML. This feature offers your users the convenience of one-click access to their AppStream 2.0 applications using their existing identity credentials. You also have the security benefit of identity authentication by your IdP. By using your IdP, you can control which users have access to a particular AppStream 2.0 stack. Refer to the remediation instructions for information on how to remove them", + "Remediation": { + "Recommendation": { + "Text": "For information on setting up SAML refer to the Setting Up SAML section of the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/external-identity-providers-setting-up-saml.html#external-identity-providers-create-saml-provider", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": userArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"userName": userName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": userArn + "/appstream-compromised-user", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userArn, + "AwsAccountId": awsAccount, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AppStream.4] AppStream 2.0 users should be configured to authenticate using SAML", + "Description": "AppStream 2.0 user " + + userName + + " is configured to authenticate using SAML.", + "Remediation": { + "Recommendation": { + "Text": "For information on setting up SAML refer to the Setting Up SAML section of the Amazon AppStream 2.0 Administration Guide", + "Url": "https://docs.aws.amazon.com/appstream2/latest/developerguide/external-identity-providers-setting-up-saml.html#external-identity-providers-create-saml-provider", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": userArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"userName": userName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_CognitoIdP_Auditor.py b/eeauditor/auditors/Amazon_CognitoIdP_Auditor.py new file mode 100644 index 00000000..cc626f66 --- /dev/null +++ b/eeauditor/auditors/Amazon_CognitoIdP_Auditor.py @@ -0,0 +1,541 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +cognitoidp = boto3.client("cognito-idp") +sts = boto3.client("sts") +# create account id & region variables +awsAccount = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] + + +class CognitoidpCisPasswordCheck(Auditor): + def execute(self): + response = cognitoidp.list_user_pools(MaxResults=60) + myCognitoUserPools = response["UserPools"] + for userpools in myCognitoUserPools: + userPoolId = str(userpools["Id"]) + response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) + userPoolArn = str(response["UserPool"]["Arn"]) + userPoolId = str(response["UserPool"]["Id"]) + cognitoPwPolicy = response["UserPool"]["Policies"]["PasswordPolicy"] + minLengthCheck = int(cognitoPwPolicy["MinimumLength"]) + uppercaseCheck = str(cognitoPwPolicy["RequireUppercase"]) + lowercaseCheck = str(cognitoPwPolicy["RequireLowercase"]) + numberCheck = str(cognitoPwPolicy["RequireNumbers"]) + symbolCheck = str(cognitoPwPolicy["RequireSymbols"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + minLengthCheck >= 14 + and uppercaseCheck == "True" + and lowercaseCheck == "True" + and numberCheck == "True" + and symbolCheck == "True" + ): + # this is a passing check + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-password-policy", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Cognito-IdP.1] Cognito user pools should have a password policy that meets or exceed AWS CIS Foundations Benchmark standards", + "Description": "Cognito user pool " + + userPoolArn + + " meets the password guidelines.", + "Remediation": { + "Recommendation": { + "Text": "To ensure you Cognito user pools have a password policy that meets or exceed AWS CIS Foundations Benchmark standards refer to the Adding User Pool Password Requirements section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-password-policy", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Cognito-IdP.1] Cognito user pools should have a password policy that meets or exceed AWS CIS Foundations Benchmark standards", + "Description": "Cognito user pool " + + userPoolArn + + " does not meet the password guidelines. Password policies, in part, enforce password complexity requirements, setting a password complexity policy increases account resiliency against brute force login attempts. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "To ensure you Cognito user pools have a password policy that meets or exceed AWS CIS Foundations Benchmark standards refer to the Adding User Pool Password Requirements section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class CognitoidpTempPasswordCheck(Auditor): + def execute(self): + response = cognitoidp.list_user_pools(MaxResults=60) + myCognitoUserPools = response["UserPools"] + for userpools in myCognitoUserPools: + userPoolId = str(userpools["Id"]) + response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) + userPoolArn = str(response["UserPool"]["Arn"]) + userPoolId = str(response["UserPool"]["Id"]) + cognitoPwPolicy = response["UserPool"]["Policies"]["PasswordPolicy"] + tempPwValidityCheck = int(cognitoPwPolicy["TemporaryPasswordValidityDays"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if tempPwValidityCheck > 1: + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-temp-password-life", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Cognito-IdP.2] Cognito user pools should not allow temporary passwords to stay valid beyond 24 hours", + "Description": "Cognito user pool " + + userPoolArn + + " allows temporary passwords to stay valid beyond 24 hours. Password policies, in part, enforce password complexity requirements, setting a password complexity policy increases account resiliency against brute force login attempts. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "To modify your Cognito user pool temporary password policy refer to the Authentication Flow for Users Created by Administrators or Developers section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-temp-password-life", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Cognito-IdP.2] Cognito user pools should not allow temporary passwords to stay valid beyond 24 hours", + "Description": "Cognito user pool " + + userPoolArn + + " does not allow temporary passwords to stay valid beyond 24 hours.", + "Remediation": { + "Recommendation": { + "Text": "To modify your Cognito user pool temporary password policy refer to the Authentication Flow for Users Created by Administrators or Developers section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class CognitoidpMfaCheck(Auditor): + def execute(self): + response = cognitoidp.list_user_pools(MaxResults=60) + myCognitoUserPools = response["UserPools"] + for userpools in myCognitoUserPools: + userPoolId = str(userpools["Id"]) + response = cognitoidp.describe_user_pool(UserPoolId=userPoolId) + userPoolArn = str(response["UserPool"]["Arn"]) + userPoolId = str(response["UserPool"]["Id"]) + mfaCheck = str(response["UserPool"]["MfaConfiguration"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if mfaCheck != "ON": + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-mfa", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Cognito-IdP.3] Cognito user pools should enforce multi factor authentication (MFA)", + "Description": "Cognito user pool " + + userPoolArn + + " does not enforce multi factor authentication (MFA). AWS recommends enabling MFA for all accounts that have a console password. Enabling MFA provides increased security for console access because it requires the authenticating principal to possess a device that emits a time-sensitive key and have knowledge of a credential. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "To ensure you Cognito user pools enforce MFA refer to the Adding Multi-Factor Authentication (MFA) to a User Pool section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": userPoolArn + "/cognito-user-pool-mfa", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": userPoolId, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Cognito-IdP.3] Cognito user pools should enforce multi factor authentication (MFA)", + "Description": "Cognito user pool " + + userPoolArn + + " enforces multi factor authentication (MFA).", + "Remediation": { + "Recommendation": { + "Text": "To ensure you Cognito user pools enforce MFA refer to the Adding Multi-Factor Authentication (MFA) to a User Pool section of the Amazon Cognito Developer Guide", + "Url": "https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCognitoUserPool", + "Id": userPoolArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"UserPoolId": userPoolId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-1", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-3", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-6", + "NIST SP 800-53 IA-7", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 IA-9", + "NIST SP 800-53 IA-10", + "NIST SP 800-53 IA-11", + "AICPA TSC CC6.1", + "AICPA TSC CC6.2", + "ISO 27001:2013 A.9.2.1", + "ISO 27001:2013 A.9.2.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.2.4", + "ISO 27001:2013 A.9.2.6", + "ISO 27001:2013 A.9.3.1", + "ISO 27001:2013 A.9.4.2", + "ISO 27001:2013 A.9.4.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_DocumentDB_Auditor.py b/eeauditor/auditors/Amazon_DocumentDB_Auditor.py new file mode 100644 index 00000000..55e8d53a --- /dev/null +++ b/eeauditor/auditors/Amazon_DocumentDB_Auditor.py @@ -0,0 +1,1330 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +documentdb = boto3.client("docdb") +sts = boto3.client("sts") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# find document db instances +response = documentdb.describe_db_instances( + Filters=[{"Name": "engine", "Values": ["docdb"]}], MaxRecords=100 +) +myDocDbs = response["DBInstances"] + + +class DocdbPublic_Instance_Check(Auditor): + def execute(self): + for docdb in myDocDbs: + docdbId = str(docdb["DBInstanceIdentifier"]) + docdbArn = str(docdb["DBInstanceArn"]) + publicAccessCheck = str(docdb["PubliclyAccessible"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if publicAccessCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-public-access", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[DocDb.1] DocumentDB instances should not be exposed to the public", + "Description": "DocumentDB instance " + + docdbId + + " is exposed to the public. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB is not intended to be public refer to the Connecting to an Amazon DocumentDB Cluster from Outside an Amazon VPC section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/connect-from-outside-a-vpc.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-public-access", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.1] DocumentDB instances should not be exposed to the public", + "Description": "DocumentDB instance " + + docdbId + + " is not exposed to the public.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB is not intended to be public refer to the Connecting to an Amazon DocumentDB Cluster from Outside an Amazon VPC section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/connect-from-outside-a-vpc.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class DocdbInstanceEncryptionCheck(Auditor): + def execute(self): + for docdb in myDocDbs: + docdbId = str(docdb["DBInstanceIdentifier"]) + docdbArn = str(docdb["DBInstanceArn"]) + encryptionCheck = str(docdb["StorageEncrypted"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if encryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[DocDb.2] DocumentDB instances should be encrypted", + "Description": "DocumentDB instance " + + docdbId + + " is not encrypted. You encrypt data at rest in your Amazon DocumentDB cluster by specifying the storage encryption option when you create your cluster. Storage encryption is enabled cluster-wide and is applied to all instances, including the primary instance and any replicas. It is also applied to your cluster’s storage volume, data, indexes, logs, automated backups, and snapshots. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB is not intended to be unencrypted refer to Encrypting Amazon DocumentDB Data at Rest in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.2] DocumentDB instances should be encrypted", + "Description": "DocumentDB instance " + docdbId + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB is not intended to be unencrypted refer to Encrypting Amazon DocumentDB Data at Rest in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class DocdbInstanceAuditLoggingCheck(Auditor): + def execute(self): + for docdb in myDocDbs: + docdbId = str(docdb["DBInstanceIdentifier"]) + docdbArn = str(docdb["DBInstanceArn"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + logCheck = str(docdb["EnabledCloudwatchLogsExports"]) + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-instance-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.3] DocumentDB instances should have audit logging configured", + "Description": "DocumentDB instance " + + docdbId + + " has audit logging configured.", + "Remediation": { + "Recommendation": { + "Text": "For information on DocumentDB audit logging refer to the Auditing Amazon DocumentDB Events section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbArn + "/docdb-instance-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[DocDb.3] DocumentDB instances should have audit logging configured", + "Description": "DocumentDB instance " + + docdbId + + " does not have audit logging configured. Profiler is useful for monitoring the slowest operations on your cluster to help you improve individual query performance and overall cluster performance. When enabled, operations are logged to Amazon CloudWatch Logs and you can use CloudWatch Insight to analyze, monitor, and archive your Amazon DocumentDB profiling data. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on DocumentDB audit logging refer to the Auditing Amazon DocumentDB Events section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbInstance", + "Id": docdbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"instanceId": docdbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class DocdbClusterMultiazCheck(Auditor): + def execute(self): + # find document db clusters + response = documentdb.describe_db_clusters(MaxRecords=100) + myDocDbClusters = response["DBClusters"] + for docdbcluster in myDocDbClusters: + docdbclusterId = str(docdbcluster["DBClusterIdentifier"]) + docdbClusterArn = str(docdbcluster["DBClusterArn"]) + multiAzCheck = str(docdbcluster["MultiAZ"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if multiAzCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbClusterArn + "/docdb-cluster-multi-az-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbclusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[DocDb.4] DocumentDB clusters should be configured for Multi-AZ", + "Description": "DocumentDB cluster " + + docdbclusterId + + " is not configured for Multi-AZ. Amazon DocumentDB helps ensure that there are instances available in your cluster in the unlikely event of an Availability Zone failure. The cluster volume for your Amazon DocumentDB cluster always spans three Availability Zones to provide durable storage with less possibility of data loss. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should be in Multi-AZ configuration refer to the Understanding Amazon DocumentDB Cluster Fault Tolerance section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-fault-tolerance.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbCluster", + "Id": docdbClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"clusterId": docdbclusterId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA-14", + "AICPA TSC A1.2", + "AICPA TSC CC3.1", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbClusterArn + "/docdb-cluster-multi-az-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.4] DocumentDB clusters should be configured for Multi-AZ", + "Description": "DocumentDB cluster " + + docdbclusterId + + " is configured for Multi-AZ.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should be in Multi-AZ configuration refer to the Understanding Amazon DocumentDB Cluster Fault Tolerance section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-fault-tolerance.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbCluster", + "Id": docdbClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"clusterId": docdbclusterId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA-14", + "AICPA TSC A1.2", + "AICPA TSC CC3.1", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class DocdbClusterDeletionProtectionCheck(Auditor): + def execute(self): + # find document db instances + response = documentdb.describe_db_clusters(MaxRecords=100) + myDocDbClusters = response["DBClusters"] + for docdbcluster in myDocDbClusters: + docdbclusterId = str(docdbcluster["DBClusterIdentifier"]) + docdbClusterArn = str(docdbcluster["DBClusterArn"]) + multiAzCheck = str(docdbcluster["MultiAZ"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if multiAzCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbClusterArn + "/docdb-cluster-deletion-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[DocDb.5] DocumentDB clusters should have deletion protection enabled", + "Description": "DocumentDB cluster " + + docdbclusterId + + " does not have deletion protection enabled. To protect your cluster from accidental deletion, you can enable deletion protection. Deletion protection is enabled by default when you create a cluster using the console. However, deletion protection is disabled by default if you create a cluster using the AWS CLI. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have deletion protection enabled refer to the Deletion Protection section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-delete.html#db-cluster-deletion-protection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbCluster", + "Id": docdbClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"clusterId": docdbclusterId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA-14", + "AICPA TSC A1.2", + "AICPA TSC CC3.1", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": docdbClusterArn + "/docdb-cluster-deletion-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": docdbClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.5] DocumentDB clusters should have deletion protection enabled", + "Description": "DocumentDB cluster " + + docdbclusterId + + " has deletion protection enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have deletion protection enabled refer to the Deletion Protection section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/db-cluster-delete.html#db-cluster-deletion-protection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDocumentDbCluster", + "Id": docdbClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"clusterId": docdbclusterId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA-14", + "AICPA TSC A1.2", + "AICPA TSC CC3.1", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class DocumentdbParameterGroupAuditLogCheck(Auditor): + def execute(self): + response = documentdb.describe_db_cluster_parameter_groups() + dbClusterParameters = response["DBClusterParameterGroups"] + for parametergroup in dbClusterParameters: + if str(parametergroup["DBParameterGroupFamily"]) == "docdb3.6": + parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) + parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) + response = documentdb.describe_db_cluster_parameters( + DBClusterParameterGroupName=parameterGroupName + ) + for parameters in response["Parameters"]: + if str(parameters["ParameterName"]) == "audit_logs": + auditLogCheck = str(parameters["ParameterValue"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if auditLogCheck == "disabled": + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/docdb-cluster-parameter-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[DocDb.6] DocumentDB cluster parameter groups should enforce audit logging for DocumentDB databases", + "Description": "DocumentDB cluster parameter group " + + parameterGroupName + + " does not enforce audit logging. Examples of logged events include successful and failed authentication attempts, dropping a collection in a database, or creating an index. By default, auditing is disabled on Amazon DocumentDB and requires that you opt in to use this feature. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have audit logging enabled refer to the Enabling Auditing section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/docdb-cluster-parameter-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.6] DocumentDB cluster parameter groups should enforce audit logging for DocumentDB databases", + "Description": "DocumentDB cluster parameter group " + + parameterGroupName + + " enforces audit logging.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have audit logging enabled refer to the Enabling Auditing section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/event-auditing.html#event-auditing-enabling-auditing", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + else: + pass + + +class DocumentdbParameterGroupTlsEnforcementCheck(Auditor): + def execute(self): + response = documentdb.describe_db_cluster_parameter_groups() + dbClusterParameters = response["DBClusterParameterGroups"] + for parametergroup in dbClusterParameters: + if str(parametergroup["DBParameterGroupFamily"]) == "docdb3.6": + parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) + parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) + response = documentdb.describe_db_cluster_parameters( + DBClusterParameterGroupName=parameterGroupName + ) + for parameters in response["Parameters"]: + if str(parameters["ParameterName"]) == "tls": + tlsEnforcementCheck = str(parameters["ParameterValue"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if tlsEnforcementCheck == "disabled": + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/docdb-cluster-parameter-tls-connections-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[DocDb.7] DocumentDB cluster parameter groups should enforce TLS connections to DocumentDB databases", + "Description": "DocumentDB cluster parameter group " + + parameterGroupName + + " does not enforce TLS connections. When encryption in transit is enabled, secure connections using TLS are required to connect to the cluster. Encryption in transit for an Amazon DocumentDB cluster is managed via the TLS parameter in a cluster parameter group. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have encryption in transit enforced refer to the Managing Amazon DocumentDB Cluster TLS Settings section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/security.encryption.ssl.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "parameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/docdb-cluster-parameter-tls-connections-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.7] DocumentDB cluster parameter groups should enforce TLS connections to DocumentDB databases", + "Description": "DocumentDB cluster parameter group " + + parameterGroupName + + " enforces TLS connections.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster should have encryption in transit enforced refer to the Managing Amazon DocumentDB Cluster TLS Settings section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/security.encryption.ssl.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "parameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + else: + pass + + +class DocumentdbClusterSnapshotEncryptionCheck(Auditor): + def execute(self): + response = documentdb.describe_db_clusters( + Filters=[{"Name": "engine", "Values": ["docdb"]}] + ) + for clusters in response["DBClusters"]: + clusterId = str(clusters["DBClusterIdentifier"]) + response = documentdb.describe_db_cluster_snapshots( + DBClusterIdentifier=clusterId + ) + for snapshots in response["DBClusterSnapshots"]: + clusterSnapshotId = str(snapshots["DBClusterSnapshotIdentifier"]) + clusterSnapshotArn = str(snapshots["DBClusterSnapshotArn"]) + encryptionCheck = str(snapshots["StorageEncrypted"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if encryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterSnapshotArn + + "/docdb-cluster-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterSnapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[DocDb.8] DocumentDB cluster snapshots should be encrypted", + "Description": "DocumentDB cluster snapshot " + + clusterSnapshotId + + " is not encrypted. You encrypt data at rest in your Amazon DocumentDB cluster by specifying the storage encryption option when you create your cluster. Storage encryption is enabled cluster-wide and is applied to all instances, including the primary instance and any replicas. It is also applied to your cluster’s storage volume, data, indexes, logs, automated backups, and snapshots. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster snapshot should be encrypted refer to the Limitations for Amazon DocumentDB Encrypted Clusters section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html#encryption-at-rest-limits", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": clusterSnapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": clusterSnapshotId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterSnapshotArn + + "/docdb-cluster-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterSnapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.8] DocumentDB cluster snapshots should be encrypted", + "Description": "DocumentDB cluster snapshot " + + clusterSnapshotId + + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster snapshot should be encrypted refer to the Limitations for Amazon DocumentDB Encrypted Clusters section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/encryption-at-rest.html#encryption-at-rest-limits", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": clusterSnapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": clusterSnapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class DocumentdbClusterSnapshotPublicShareCheck(Auditor): + def execute(self): + response = documentdb.describe_db_clusters( + Filters=[{"Name": "engine", "Values": ["docdb"]}] + ) + for clusters in response["DBClusters"]: + clusterId = str(clusters["DBClusterIdentifier"]) + response = documentdb.describe_db_cluster_snapshots( + DBClusterIdentifier=clusterId + ) + for snapshots in response["DBClusterSnapshots"]: + clusterSnapshotId = str(snapshots["DBClusterSnapshotIdentifier"]) + clusterSnapshotArn = str(snapshots["DBClusterSnapshotArn"]) + response = documentdb.describe_db_cluster_snapshot_attributes( + DBClusterSnapshotIdentifier=clusterSnapshotId + ) + for snapshotattributes in response["DBClusterSnapshotAttributesResult"][ + "DBClusterSnapshotAttributes" + ]: + if str(snapshotattributes["AttributeName"]) == "restore": + valueCheck = str(snapshotattributes["AttributeValues"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if valueCheck == "['all']": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterSnapshotArn + + "/docdb-cluster-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterSnapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[DocDb.9] DocumentDB cluster snapshots should not be publicly shared", + "Description": "DocumentDB cluster snapshot " + + clusterSnapshotId + + " is publicly shared. You can share a manual snapshot with up to 20 other AWS accounts. You can also share an unencrypted manual snapshot as public, which makes the snapshot available to all accounts. Take care when sharing a snapshot as public so that none of your private information is included in any of your public snapshots. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster snapshot should not be publicly shared refer to the Sharing Amazon DocumentDB Cluster Snapshots section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshot-share.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": clusterSnapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"snapshotId": clusterSnapshotId} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterSnapshotArn + + "/docdb-cluster-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterSnapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[DocDb.9] DocumentDB cluster snapshots should not be publicly shared", + "Description": "DocumentDB cluster snapshot " + + clusterSnapshotId + + " is not publicly shared, however, it may be shared with other accounts. You should periodically review who has snapshots shared with them to ensure they are still authorized", + "Remediation": { + "Recommendation": { + "Text": "If your DocumentDB cluster snapshot should not be publicly shared refer to the Sharing Amazon DocumentDB Cluster Snapshots section in the Amazon DocumentDB Developer Guide", + "Url": "https://docs.aws.amazon.com/documentdb/latest/developerguide/backup-restore.db-cluster-snapshot-share.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": clusterSnapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"snapshotId": clusterSnapshotId} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass diff --git a/eeauditor/auditors/Amazon_EBS_Auditor.py b/eeauditor/auditors/Amazon_EBS_Auditor.py new file mode 100644 index 00000000..d52356b7 --- /dev/null +++ b/eeauditor/auditors/Amazon_EBS_Auditor.py @@ -0,0 +1,885 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +ec2 = boto3.client("ec2") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through EBS volumes +response = ec2.describe_volumes(DryRun=False, MaxResults=500) +myEbsVolumes = response["Volumes"] +# loop through EBS snapshots +response = ec2.describe_snapshots(OwnerIds=[awsAccountId], DryRun=False) +myEbsSnapshots = response["Snapshots"] + + +class EbsVolumeAttachmentCheck(Auditor): + def execute(self): + for volumes in myEbsVolumes: + ebsVolumeId = str(volumes["VolumeId"]) + ebsVolumeArn = ( + "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId + ) + ebsAttachments = volumes["Attachments"] + for attachments in ebsAttachments: + ebsAttachmentState = str(attachments["State"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ebsAttachmentState != "attached": + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-attachment-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EBS.1] EBS Volumes should be in an attached state", + "Description": "EBS Volume " + + ebsVolumeId + + " is not in an attached state. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be attached refer to the Attaching an Amazon EBS Volume to an Instance section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-attachment-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.1] EBS Volumes should be in an attached state", + "Description": "EBS Volume " + + ebsVolumeId + + " is in an attached state.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be attached refer to the Attaching an Amazon EBS Volume to an Instance section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-attaching-volume.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EbsVolumeDeleteOnTerminationCheck(Auditor): + def execute(self): + for volumes in myEbsVolumes: + ebsVolumeId = str(volumes["VolumeId"]) + ebsVolumeArn = ( + "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId + ) + ebsAttachments = volumes["Attachments"] + for attachments in ebsAttachments: + ebsDeleteOnTerminationCheck = str(attachments["DeleteOnTermination"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ebsDeleteOnTerminationCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-delete-on-termination-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EBS.2] EBS Volumes should be configured to be deleted on termination", + "Description": "EBS Volume " + + ebsVolumeId + + " is not configured to be deleted on termination. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be deleted on instance termination refer to the Preserving Amazon EBS Volumes on Instance Termination section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#preserving-volumes-on-termination", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-delete-on-termination-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.2] EBS Volumes should be configured to be deleted on termination", + "Description": "EBS Volume " + + ebsVolumeId + + " is configured to be deleted on termination.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be deleted on instance termination refer to the Preserving Amazon EBS Volumes on Instance Termination section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/terminating-instances.html#preserving-volumes-on-termination", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EbsVolumeEncryptionCheck(Auditor): + def execute(self): + for volumes in myEbsVolumes: + ebsVolumeId = str(volumes["VolumeId"]) + ebsVolumeArn = ( + "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + "/" + ebsVolumeId + ) + ebsEncryptionCheck = str(volumes["Encrypted"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ebsEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EBS.3] EBS Volumes should be encrypted", + "Description": "EBS Volume " + + ebsVolumeId + + " is not encrypted. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be encrypted refer to the Amazon EBS Encryption section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ebsVolumeArn + "/ebs-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ebsVolumeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.3] EBS Volumes should be encrypted", + "Description": "EBS Volume " + ebsVolumeId + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS volume should be encrypted refer to the Amazon EBS Encryption section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Volume", + "Id": ebsVolumeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"volumeId": ebsVolumeId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EbsSnapshotEncryptionCheck(Auditor): + def execute(self): + for snapshots in myEbsSnapshots: + snapshotId = str(snapshots["SnapshotId"]) + snapshotArn = "arn:aws:ec2:" + awsRegion + "::snapshot/" + snapshotId + snapshotEncryptionCheck = str(snapshots["Encrypted"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if snapshotEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/ebs-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EBS.4] EBS Snapshots should be encrypted", + "Description": "EBS Snapshot " + + snapshotId + + " is not encrypted. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your EBS snapshot should be encrypted refer to the Encryption Support for Snapshots section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/EBSSnapshots.html#encryption-support", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Snapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/ebs-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.4] EBS Snapshots should be encrypted", + "Description": "EBS Snapshot " + snapshotId + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS snapshot should be encrypted refer to the Encryption Support for Snapshots section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/EBSSnapshots.html#encryption-support", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Snapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EbsSnapshotPublicCheck(Auditor): + def execute(self): + for snapshots in myEbsSnapshots: + snapshotId = str(snapshots["SnapshotId"]) + snapshotArn = "arn:aws:ec2:" + awsRegion + "::snapshot/" + snapshotId + response = ec2.describe_snapshot_attribute( + Attribute="createVolumePermission", SnapshotId=snapshotId, DryRun=False + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if str(response["CreateVolumePermissions"]) == "[]": + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/ebs-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.5] EBS Snapshots should not be public", + "Description": "EBS Snapshot " + snapshotId + " is private.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Snapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + for permissions in response["CreateVolumePermissions"]: + # {'Group': 'all'} denotes public + # you should still audit accounts you have shared + if str(permissions) == "{'Group': 'all'}": + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/ebs-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[EBS.5] EBS Snapshots should not be public", + "Description": "EBS Snapshot " + + snapshotId + + " is public. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Snapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"snapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/ebs-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.5] EBS Snapshots should not be public", + "Description": "EBS Snapshot " + + snapshotId + + " is private, however, this snapshot has been identified as being shared with other accounts. You should audit these accounts to ensure they are still authorized to have this snapshot shared with them.", + "Remediation": { + "Recommendation": { + "Text": "If your EBS snapshot should not be public refer to the Sharing an Amazon EBS Snapshot section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ebs-modifying-snapshot-permissions.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Snapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"SnapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class EbsAccountEncryptionByDefaultCheck(Auditor): + def execute(self): + response = ec2.get_ebs_encryption_by_default(DryRun=False) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + ) + if str(response["EbsEncryptionByDefault"]) == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + awsRegion + "/ebs-account-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId + "/" + awsRegion, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EBS.6] Account-level EBS Volume encryption should be enabled", + "Description": "Account-level EBS volume encryption is not enabled for AWS Account " + + awsAccountId + + " in " + + awsRegion + + ". Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on Account-level encryption refer to the Encryption by Default to an Instance section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html#encryption-by-default", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + awsRegion + "/ebs-account-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId + "/" + awsRegion, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EBS.6] Account-level EBS Volume encryption should be enabled", + "Description": "Account-level EBS volume encryption is enabled for AWS Account " + + awsAccountId + + " in " + + awsRegion + + ".", + "Remediation": { + "Recommendation": { + "Text": "For information on Account-level encryption refer to the Encryption by Default to an Instance section of the Amazon Elastic Compute Cloud User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html#encryption-by-default", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_EC2_Auditor.py b/eeauditor/auditors/Amazon_EC2_Auditor.py new file mode 100644 index 00000000..cb373afe --- /dev/null +++ b/eeauditor/auditors/Amazon_EC2_Auditor.py @@ -0,0 +1,199 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +sts = boto3.client("sts") +ec2 = boto3.client("ec2") +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] + + +class Ec2Imdsv2Check(Auditor): + def execute(self): + try: + response = ec2.describe_instances(MaxResults=1000) + for r in response["Reservations"]: + for i in r["Instances"]: + instanceId = str(i["InstanceId"]) + instanceArn = ( + "arn:aws:ec2:" + awsRegion + ":" + awsAccountId + ":instance/" + instanceId + ) + instanceType = str(i["InstanceType"]) + instanceImage = str(i["ImageId"]) + subnetId = str(i["SubnetId"]) + vpcId = str(i["VpcId"]) + instanceLaunchedAt = str(i["LaunchTime"]) + metadataServiceCheck = str(i["MetadataOptions"]["HttpEndpoint"]) + if metadataServiceCheck == "enabled": + imdsv2Check = str(i["MetadataOptions"]["HttpTokens"]) + if imdsv2Check != "required": + try: + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-imdsv2-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EC2.1] EC2 Instances should be configured to use instance metadata service V2 (IMDSv2)", + "Description": "EC2 Instance " + + instanceId + + " is not configured to use instance metadata service V2 (IMDSv2). IMDSv2 adds new “belt and suspenders” protections for four types of vulnerabilities that could be used to try to access the IMDS. These new protections go well beyond other types of mitigations, while working seamlessly with existing mitigations such as restricting IAM roles and using local firewall rules to restrict access to the IMDS. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "To learn how to configure IMDSv2 refer to the Transitioning to Using Instance Metadata Service Version 2 section of the Amazon EC2 User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-transition-to-version-2", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": vpcId, + "SubnetId": subnetId, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-4", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-5", + "NIST SP 800-53 AC-6", + "NIST SP 800-53 AC-14", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-24", + "AICPA TSC CC6.3", + "ISO 27001:2013 A.6.1.2", + "ISO 27001:2013 A.9.1.2", + "ISO 27001:2013 A.9.2.3", + "ISO 27001:2013 A.9.4.1", + "ISO 27001:2013 A.9.4.4", + "ISO 27001:2013 A.9.4.5", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # create Sec Hub finding + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-imdsv2-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EC2.1] EC2 Instances should be configured to use instance metadata service V2 (IMDSv2)", + "Description": "EC2 Instance " + + instanceId + + " is using instance metadata service V2 (IMDSv2). IMDSv2 adds new “belt and suspenders” protections for four types of vulnerabilities that could be used to try to access the IMDS. These new protections go well beyond other types of mitigations, while working seamlessly with existing mitigations such as restricting IAM roles and using local firewall rules to restrict access to the IMDS. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "To learn how to configure IMDSv2 refer to the Transitioning to Using Instance Metadata Service Version 2 section of the Amazon EC2 User Guide", + "Url": "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html#instance-metadata-transition-to-version-2", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": vpcId, + "SubnetId": subnetId, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": ["NIST CSF PR.PT-3"], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + else: + pass + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_EC2_SSM_Auditor.py b/eeauditor/auditors/Amazon_EC2_SSM_Auditor.py new file mode 100644 index 00000000..fc8d0e04 --- /dev/null +++ b/eeauditor/auditors/Amazon_EC2_SSM_Auditor.py @@ -0,0 +1,759 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# create boto3 clients +sts = boto3.client("sts") +ec2 = boto3.client("ec2") +ssm = boto3.client("ssm") +securityhub = boto3.client("securityhub") +# create env vars +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through ec2 instances +response = ec2.describe_instances(DryRun=False, MaxResults=1000) +myEc2InstanceReservations = response["Reservations"] + + +class Ec2InstanceSsmManagedCheck(Auditor): + def execute(self): + for reservations in myEc2InstanceReservations: + for instances in reservations["Instances"]: + instanceId = str(instances["InstanceId"]) + instanceArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":instance/" + + instanceId + ) + instanceType = str(instances["InstanceType"]) + instanceImage = str(instances["ImageId"]) + instanceVpc = str(instances["VpcId"]) + instanceSubnet = str(instances["SubnetId"]) + instanceLaunchedAt = str(instances["LaunchTime"]) + try: + response = ssm.describe_instance_information( + InstanceInformationFilterList=[ + {"key": "InstanceIds", "valueSet": [instanceId]}, + ] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if str(response["InstanceInformationList"]) == "[]": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-managed-by-ssm-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EC2-SSM.1] EC2 Instances should be managed by Systems Manager", + "Description": "EC2 Instance " + + instanceId + + " is not managed by Systems Manager. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "To learn how to configure Systems Manager and associated instances refer to the Setting Up AWS Systems Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/en_us/systems-manager/latest/userguide/systems-manager-setting-up.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-managed-by-ssm-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EC2-SSM.1] EC2 Instances should be managed by Systems Manager", + "Description": "EC2 Instance " + + instanceId + + " is managed by Systems Manager.", + "Remediation": { + "Recommendation": { + "Text": "To learn how to configure Systems Manager and associated instances refer to the Setting Up AWS Systems Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/en_us/systems-manager/latest/userguide/systems-manager-setting-up.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class SsmInstaceAgentUpdateCheck(Auditor): + def execute(self): + for reservations in myEc2InstanceReservations: + for instances in reservations["Instances"]: + instanceId = str(instances["InstanceId"]) + instanceArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":instance/" + + instanceId + ) + instanceType = str(instances["InstanceType"]) + instanceImage = str(instances["ImageId"]) + instanceVpc = str(instances["VpcId"]) + instanceSubnet = str(instances["SubnetId"]) + instanceLaunchedAt = str(instances["LaunchTime"]) + response = ssm.describe_instance_information() + myManagedInstances = response["InstanceInformationList"] + for instances in myManagedInstances: + latestVersionCheck = str(instances["IsLatestVersion"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if latestVersionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-ssm-agent-latest-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EC2-SSM.2] EC2 Instances managed by Systems Manager should have the latest SSM Agent installed", + "Description": "EC2 Instance " + + instanceId + + " does not have the latest SSM Agent installed. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on automating updates to the SSM Agent refer to the Automate Updates to SSM Agent section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-automatic-updates.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-ssm-agent-latest-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EC2-SSM.2] EC2 Instances managed by Systems Manager should have the latest SSM Agent installed", + "Description": "EC2 Instance " + + instanceId + + " has the latest SSM Agent installed.", + "Remediation": { + "Recommendation": { + "Text": "For information on automating updates to the SSM Agent refer to the Automate Updates to SSM Agent section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-automatic-updates.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class SsmInstanceAssociationCheck(Auditor): + def execute(self): + for reservations in myEc2InstanceReservations: + for instances in reservations["Instances"]: + instanceId = str(instances["InstanceId"]) + instanceArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":instance/" + + instanceId + ) + instanceType = str(instances["InstanceType"]) + instanceImage = str(instances["ImageId"]) + instanceVpc = str(instances["VpcId"]) + instanceSubnet = str(instances["SubnetId"]) + instanceLaunchedAt = str(instances["LaunchTime"]) + response = ssm.describe_instance_information() + myManagedInstances = response["InstanceInformationList"] + for instances in myManagedInstances: + associationStatusCheck = str(instances["AssociationStatus"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if associationStatusCheck != "Success": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-ssm-association-success-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EC2-SSM.3] EC2 Instances managed by Systems Manager should have a successful Association status", + "Description": "EC2 Instance " + + instanceId + + " does not have a successful Association status. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on Systems Manager Associations refer to the Working with Associations in Systems Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-associations.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-ssm-association-success-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EC2-SSM.3] EC2 Instances managed by Systems Manager should have a successful Association status", + "Description": "EC2 Instance " + + instanceId + + " has a successful Association status.", + "Remediation": { + "Recommendation": { + "Text": "For information on Systems Manager Associations refer to the Working with Associations in Systems Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-associations.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class SsmInstancePatchStateState(Auditor): + def execute(self): + for reservations in myEc2InstanceReservations: + for instances in reservations["Instances"]: + instanceId = str(instances["InstanceId"]) + instanceArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":instance/" + + instanceId + ) + instanceType = str(instances["InstanceType"]) + instanceImage = str(instances["ImageId"]) + instanceVpc = str(instances["VpcId"]) + instanceSubnet = str(instances["SubnetId"]) + instanceLaunchedAt = str(instances["LaunchTime"]) + response = ssm.describe_instance_information() + try: + response = ssm.describe_instance_patch_states( + InstanceIds=[instanceId] + ) + patchStatesCheck = str(response["InstancePatchStates"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if patchStatesCheck == "[]": + print("no patch info") + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-patch-manager-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", + "Description": "EC2 Instance " + + instanceId + + " does not have any patch information recorded and is likely not managed by Patch Manager. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + patchStates = response["InstancePatchStates"] + for patches in patchStates: + failedPatchCheck = str(patches["FailedCount"]) + missingPatchCheck = str(patches["MissingCount"]) + if failedPatchCheck != "0" or missingPatchCheck != "0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-patch-manager-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", + "Description": "EC2 Instance " + + instanceId + + " is missing patches or has patches that failed to apply. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/ec2-patch-manager-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EC2-SSM.4] EC2 Instances managed by Systems Manager should have the latest patches installed by Patch Manager", + "Description": "EC2 Instance " + + instanceId + + " has the latest patches installed by Patch Manager.", + "Remediation": { + "Recommendation": { + "Text": "For information on Patch Manager refer to the AWS Systems Manager Patch Manager section of the AWS Systems Manager User Guide", + "Url": "https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": instanceType, + "ImageId": instanceImage, + "VpcId": instanceVpc, + "SubnetId": instanceSubnet, + "LaunchedAt": instanceLaunchedAt, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_EC2_Security_Group_Auditor.py b/eeauditor/auditors/Amazon_EC2_Security_Group_Auditor.py new file mode 100644 index 00000000..0c93625c --- /dev/null +++ b/eeauditor/auditors/Amazon_EC2_Security_Group_Auditor.py @@ -0,0 +1,4068 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +ec2 = boto3.client("ec2") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through security groups +response = ec2.describe_security_groups() +mySgs = response["SecurityGroups"] + + +class SecurityGroupAllOpenCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ipProtocol == "-1" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-all-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.1] Security groups should not allow unrestricted access to all ports and protocols", + "Description": "Security group " + + sgName + + " allows unrestricted access to all ports and protocols. Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif ipProtocol == "-1" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-all-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.1] Security groups should not allow unrestricted access to all ports and protocols", + "Description": "Security group " + + sgName + + " does not allow unrestricted access to all ports and protocols. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenFtpCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + toPort == "20" + and fromPort == "21" + and cidrIpRange == "0.0.0.0/0" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-ftp-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.2] Security groups should not allow unrestricted File Transfer Protocol (FTP) access", + "Description": "Security group " + + sgName + + " allows unrestricted File Transfer Protocol (FTP) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif ( + toPort == "20" + and fromPort == "21" + and cidrIpRange != "0.0.0.0/0" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-ftp-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.2] Security groups should not allow unrestricted File Transfer Protocol (FTP) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted File Transfer Protocol (FTP) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenTelnetCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "23" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-telnet-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.3] Security groups should not allow unrestricted TelNet access", + "Description": "Security group " + + sgName + + " allows unrestricted TelNet access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "23" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-telnet-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.3] Security groups should not allow unrestricted TelNet access", + "Description": "Security group " + + sgName + + " does not allow unrestricted TelNet access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenDcomRpcCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "135" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-telnet-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.4] Security groups should not allow unrestricted Windows RPC DCOM access", + "Description": "Security group " + + sgName + + " allows unrestricted Windows RPC DCOM access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Attack signature information, refer to Threatl Intel Source URL", + "Source": "Symantec Security Center", + "SourceUrl": "https://www.symantec.com/security_response/attacksignatures/detail.jsp?asid=20387", + } + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + if toPort and fromPort == "135" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-wsrpc-dcom-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.4] Security groups should not allow unrestricted Windows RPC DCOM access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Windows RPC DCOM access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Attack signature information, refer to Threatl Intel Source URL", + "Source": "Symantec Security Center", + "SourceUrl": "https://www.symantec.com/security_response/attacksignatures/detail.jsp?asid=20387", + } + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenSmbCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "445" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-smb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.5] Security groups should not allow unrestricted Server Message Blocks (SMB) access", + "Description": "Security group " + + sgName + + " allows unrestricted Server Message Blocks (SMB) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/modules/exploit/windows/smb/ms17_010_eternalblue", + }, + { + "Category": "BACKDOOR", + "Value": "How to use EternalBlue to Exploit SMB Port using Public Wi-Fi", + "Source": "Medium", + "SourceUrl": "https://medium.com/@melvinshb/how-to-use-eternalblue-to-exploit-smb-port-using-public-wi-fi-79a996821767", + }, + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "445" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-smb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.5] Security groups should not allow unrestricted Server Message Blocks (SMB) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Server Message Blocks (SMB) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "MS17-010 EternalBlue SMB Remote Windows Kernel Pool Corruption", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/modules/exploit/windows/smb/ms17_010_eternalblue", + }, + { + "Category": "BACKDOOR", + "Value": "How to use EternalBlue to Exploit SMB Port using Public Wi-Fi", + "Source": "Medium", + "SourceUrl": "https://medium.com/@melvinshb/how-to-use-eternalblue-to-exploit-smb-port-using-public-wi-fi-79a996821767", + }, + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenMssqlCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "1433" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-mssql-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.6] Security groups should not allow unrestricted Microsoft SQL Server (MSSQL) access", + "Description": "Security group " + + sgName + + " allows unrestricted Microsoft SQL Server (MSSQL) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0618: Microsoft SQL Server Reporting Services Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0618", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2019-0819: Microsoft SQL Server Analysis Services Information Disclosure Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2019-0819", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2018-8273: Microsoft SQL Server Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2018-8273", + }, + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "1433" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-mssql-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.6] Security groups should not allow unrestricted Microsoft SQL Server (MSSQL) access", + "Description": "Security group " + + sgName + + " allows unrestricted Microsoft SQL Server (MSSQL) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0618: Microsoft SQL Server Reporting Services Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0618", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2019-0819: Microsoft SQL Server Analysis Services Information Disclosure Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2019-0819", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2018-8273: Microsoft SQL Server Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2018-8273", + }, + ], + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenOracleCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "1521" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-oracledb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.7] Security groups should not allow unrestricted Oracle database (TCP 1521) access", + "Description": "Security group " + + sgName + + " allows unrestricted Oracle database (TCP 1521) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "1521" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-oracledb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.7] Security groups should not allow unrestricted Oracle database (TCP 1521) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Oracle database (TCP 1521) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenMysqlMariadbCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "3306" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-mysql-mariadb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.8] Security groups should not allow unrestricted MySQL or MariaDB database (TCP 3306) access", + "Description": "Security group " + + sgName + + " allows unrestricted MySQL or MariaDB database (TCP 3306) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + if toPort and fromPort == "3306" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-mysql-mariadb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.8] Security groups should not allow unrestricted MySQL or MariaDB database (TCP 3306) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted MySQL or MariaDB database (TCP 3306) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenRdpCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "3389" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-rdp-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.9] Security groups should not allow unrestricted Remote Desktop Protocol (RDP) access", + "Description": "Security group " + + sgName + + " allows unrestricted Remote Desktop Protocol (RDP) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0660: Windows Remote Desktop Protocol (RDP) Denial of Service Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0610: Windows Remote Desktop Gateway (RD Gateway) Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0610", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "3389" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-rdp-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.9] Security groups should not allow unrestricted Remote Desktop Protocol (RDP) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Remote Desktop Protocol (RDP) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0660: Windows Remote Desktop Protocol (RDP) Denial of Service Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", + }, + { + "Category": "BACKDOOR", + "Value": "Microsoft CVE-2020-0610: Windows Remote Desktop Gateway (RD Gateway) Remote Code Execution Vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0610", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenPostgresqlCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "5432" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-postgresql-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.10] Security groups should not allow unrestricted PostgreSQL datbase (TCP 5432) access", + "Description": "Security group " + + sgName + + " allows unrestricted PostgreSQL datbase (TCP 5432) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "5432" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-postgresql-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.10] Security groups should not allow unrestricted PostgreSQL datbase (TCP 5432) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted PostgreSQL datbase (TCP 5432) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenKibanaCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "5601" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-kibana-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.11] Security groups should not allow unrestricted access to Kibana (TCP 5601)", + "Description": "Security group " + + sgName + + " allows unrestricted access to Kibana (TCP 5601) on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "CVE-2019-7609: Exploit Script Available for Kibana Remote Code Execution Vulnerability", + "Source": "Tenable Blog", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", + }, + { + "Category": "BACKDOOR", + "Value": "Red Hat OpenShift: CVE-2019-7608: kibana: Cross-site scripting vulnerability permits perform destructive actions on behalf of other Kibana users", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redhat-openshift-cve-2019-7608", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "5601" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-kibana-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.11] Security groups should not allow unrestricted access to Kibana (TCP 5601)", + "Description": "Security group " + + sgName + + " does not allow unrestricted access to Kibana (TCP 5601) on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "CVE-2019-7609: Exploit Script Available for Kibana Remote Code Execution Vulnerability", + "Source": "Tenable Blog", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/msft-cve-2020-0660", + }, + { + "Category": "BACKDOOR", + "Value": "Red Hat OpenShift: CVE-2019-7608: kibana: Cross-site scripting vulnerability permits perform destructive actions on behalf of other Kibana users", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redhat-openshift-cve-2019-7608", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenRedisCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "6379" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-redis-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.12] Security groups should not allow unrestricted Redis (TCP 6379) access", + "Description": "Security group " + + sgName + + " allows unrestricted Redis (TCP 6379) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Redis 4.x / 5.x - Unauthenticated Code Execution (Metasploit)", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/47195", + }, + { + "Category": "BACKDOOR", + "Value": "Redis: Improper Input Validation (CVE-2013-0178)", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redislabs-redis-cve-2013-0178", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "6379" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-redis-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.12] Security groups should not allow unrestricted Redis (TCP 6379) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Redis (TCP 6379) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Redis 4.x / 5.x - Unauthenticated Code Execution (Metasploit)", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/47195", + }, + { + "Category": "BACKDOOR", + "Value": "Redis: Improper Input Validation (CVE-2013-0178)", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/redislabs-redis-cve-2013-0178", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenSplunkdCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "8089" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-splunkd-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.13] Security groups should not allow unrestricted Splunkd (TCP 8089) access", + "Description": "Security group " + + sgName + + " allows unrestricted Splunkd (TCP 8089) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Splunk - Remote Command Execution", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/18245", + }, + { + "Category": "BACKDOOR", + "Value": "Splunk Web Interface Login Utility", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/modules/auxiliary/scanner/http/splunk_web_login", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "8089" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-splunkd-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.13] Security groups should not allow unrestricted Splunkd (TCP 8089) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Splunkd (TCP 8089) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "Splunk - Remote Command Execution", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/18245", + }, + { + "Category": "BACKDOOR", + "Value": "Splunk Web Interface Login Utility", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/modules/auxiliary/scanner/http/splunk_web_login", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenElasticsearch1Check(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "9200" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-elasticsearch-9200-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.14] Security groups should not allow unrestricted Elasticsearch (TCP 9200) access", + "Description": "Security group " + + sgName + + " allows unrestricted Elasticsearch (TCP 9200) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "9200" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-elasticsearch-9200-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.14] Security groups should not allow unrestricted Elasticsearch (TCP 9200) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Elasticsearch (TCP 9200) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenElasticsearch2Check(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "9300" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-elasticsearch-9300-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.15] Security groups should not allow unrestricted Elasticsearch (TCP 9300) access", + "Description": "Security group " + + sgName + + " allows unrestricted Elasticsearch (TCP 9300) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "9300" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-elasticsearch-9300-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.15] Security groups should not allow unrestricted Elasticsearch (TCP 9300) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Elasticsearch (TCP 9300) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenMemcachedCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + toPort + and fromPort == "11211" + and ipProtocol == "udp" + and cidrIpRange == "0.0.0.0/0" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-memcached-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.16] Security groups should not allow unrestricted Memcached (UDP 11211) access", + "Description": "Security group " + + sgName + + " allows unrestricted Memcached (UDP 11211) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "memcached 1.4.2 - Memory Consumption Remote Denial of Service", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/33850", + }, + { + "Category": "BACKDOOR", + "Value": "Ubuntu: USN-4125-1 (CVE-2019-15026): Memcached vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/ubuntu-cve-2019-15026", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif ( + toPort + and fromPort == "11211" + and ipProtocol == "udp" + and cidrIpRange != "0.0.0.0/0" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-memcached-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.16] Security groups should not allow unrestricted Memcached (UDP 11211) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Memcached (UDP 11211) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Category": "BACKDOOR", + "Value": "memcached 1.4.2 - Memory Consumption Remote Denial of Service", + "Source": "ExploitDB", + "SourceUrl": "https://www.exploit-db.com/exploits/33850", + }, + { + "Category": "BACKDOOR", + "Value": "Ubuntu: USN-4125-1 (CVE-2019-15026): Memcached vulnerability", + "Source": "Rapid7 Vulnerability & Exploit Database", + "SourceUrl": "https://www.rapid7.com/db/vulnerabilities/ubuntu-cve-2019-15026", + }, + ], + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenRedshiftCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "5439" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-redshift-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.17] Security groups should not allow unrestricted Redshift (TCP 5439) access", + "Description": "Security group " + + sgName + + " allows unrestricted Redshift (TCP 5439) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "5439" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-redshift-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.17] Security groups should not allow unrestricted Redshift (TCP 5439) access", + "Description": "Security group " + + sgName + + " does not allow unrestricted Redshift (TCP 5439) access on " + + ipProtocol + + ". Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenDocumentdbCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "27017" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-documentdb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.18] Security groups should not allow unrestricted DocumentDB (TCP 27017) access", + "Description": "Security group " + + sgName + + " allows unrestricted DocumentDB (TCP 27017) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "27017" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-documentdb-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.18] Security groups should not allow unrestricted DocumentDB (TCP 27017) access", + "Description": "Security group " + + sgName + + " allows unrestricted DocumentDB (TCP 27017) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenCassandraCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "9142" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-cassandra-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.19] Security groups should not allow unrestricted Cassandra (TCP 9142) access", + "Description": "Security group " + + sgName + + " allows unrestricted Cassandra (TCP 9142) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "9142" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-cassandra-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.19] Security groups should not allow unrestricted Cassandra (TCP 9142) access", + "Description": "Security group " + + sgName + + " allows unrestricted Cassandra (TCP 9142) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class SecurityGroupOpenKafkaCheck(Auditor): + def execute(self): + for secgroup in mySgs: + sgName = str(secgroup["GroupName"]) + sgId = str(secgroup["GroupId"]) + sgArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":security-group/" + + sgId + ) + for permissions in secgroup["IpPermissions"]: + try: + fromPort = str(permissions["FromPort"]) + except Exception as e: + if str(e) == "'FromPort'": + pass + else: + print(e) + try: + toPort = str(permissions["ToPort"]) + except Exception as e: + if str(e) == "'ToPort'": + pass + else: + print(e) + try: + ipProtocol = str(permissions["IpProtocol"]) + except Exception as e: + print(e) + ipRanges = permissions["IpRanges"] + for cidrs in ipRanges: + cidrIpRange = str(cidrs["CidrIp"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if toPort and fromPort == "9092" and cidrIpRange == "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-kafka-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[SecurityGroup.20] Security groups should not allow unrestricted Kafka streams (TCP 9092) access", + "Description": "Security group " + + sgName + + " allows unrestricted Kafka streams (TCP 9092) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif toPort and fromPort == "9092" and cidrIpRange != "0.0.0.0/0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": sgArn + + "/" + + ipProtocol + + "/security-group-kafka-open-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": sgArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SecurityGroup.20] Security groups should not allow unrestricted Kafka streams (TCP 9092) access", + "Description": "Security group " + + sgName + + " allows unrestricted Kafka streams (TCP 9092) access on " + + ipProtocol + + ". Refer to the remediation instructions to remediate this behavior. Your security group should still be audited to ensure any other rules are compliant with organizational or regulatory requirements.", + "Remediation": { + "Recommendation": { + "Text": "For more information on modifying security group rules refer to the Adding, Removing, and Updating Rules section of the Amazon Virtual Private Cloud User Guide", + "Url": "https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html#AddRemoveRules", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2SecurityGroup", + "Id": sgArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2SecurityGroup": { + "GroupName": sgName, + "GroupId": sgId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass diff --git a/eeauditor/auditors/Amazon_ECR_Auditor.py b/eeauditor/auditors/Amazon_ECR_Auditor.py new file mode 100644 index 00000000..48e61faa --- /dev/null +++ b/eeauditor/auditors/Amazon_ECR_Auditor.py @@ -0,0 +1,610 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +ecr = boto3.client("ecr") +sts = boto3.client("sts") +# create account id & region variables +awsAccount = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through ECR repos +response = ecr.describe_repositories(maxResults=1000) +myRepos = response["repositories"] + + +class EcrRepoVulnScanCheck(Auditor): + def execute(self): + for repo in myRepos: + repoArn = str(repo["repositoryArn"]) + repoName = str(repo["repositoryName"]) + scanningConfig = str(repo["imageScanningConfiguration"]["scanOnPush"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if scanningConfig == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-no-scan", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ECR.1] ECR repositories should be configured to scan images on push", + "Description": "ECR repository " + + repoName + + " is not configured to scan images on push. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to scan on push refer to the Image Scanning section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.CM-8", + "NIST SP 800-53 RA-5", + "AICPA TSC CC7.1", + "ISO 27001:2013 A.12.6.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-no-scan", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECR.1] ECR repositories should be configured to scan images on push", + "Description": "ECR repository " + + repoName + + " is configured to scan images on push.", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to scan on push refer to the Image Scanning section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.CM-8", + "NIST SP 800-53 RA-5", + "AICPA TSC CC7.1", + "ISO 27001:2013 A.12.6.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EcrRepoImageLifecyclePolicyCheck(Auditor): + def execute(self): + for repo in myRepos: + repoArn = str(repo["repositoryArn"]) + repoName = str(repo["repositoryName"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing finding + response = ecr.get_lifecycle_policy(repositoryName=repoName) + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-lifecycle-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECR.2] ECR repositories should be have an image lifecycle policy configured", + "Description": "ECR repository " + + repoName + + " does not have an image lifecycle policy configured. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to have an image lifecycle policy refer to the Amazon ECR Lifecycle Policies section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-lifecycle-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ECR.2] ECR repositories should be have an image lifecycle policy configured", + "Description": "ECR repository " + + repoName + + " does not have an image lifecycle policy configured. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to have an image lifecycle policy refer to the Amazon ECR Lifecycle Policies section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class EcrRepoPermissionPolicy(Auditor): + def execute(self): + for repo in myRepos: + repoArn = str(repo["repositoryArn"]) + repoName = str(repo["repositoryName"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing finding + response = ecr.get_repository_policy(repositoryName=repoName) + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-repo-access-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECR.3] ECR repositories should be have a repository policy configured", + "Description": "ECR repository " + + repoName + + " has a repository policy configured.", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to have a repository policy refer to the Amazon ECR Repository Policies section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoArn + "/ecr-repo-access-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": repoArn, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ECR.3] ECR repositories should be have a repository policy configured", + "Description": "ECR repository " + + repoName + + " does not have a repository policy configured. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your repository should be configured to have a repository policy refer to the Amazon ECR Repository Policies section in the Amazon ECR User Guide", + "Url": "https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcrRepository", + "Id": repoArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"RepositoryName": repoName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class EcrLatestImageVulnCheck(Auditor): + def execute(self): + for repo in myRepos: + repoArn = str(repo["repositoryArn"]) + repoName = str(repo["repositoryName"]) + scanningConfig = str(repo["imageScanningConfiguration"]["scanOnPush"]) + if scanningConfig == "True": + try: + response = ecr.describe_images( + repositoryName=repoName, + filter={"tagStatus": "TAGGED"}, + maxResults=1000, + ) + for images in response["imageDetails"]: + imageDigest = str(images["imageDigest"]) + # use the first tag only as we need it to create the canonical ID for the Resource.Id in the ASFF for the Container Resource.Type + imageTag = str(images["imageTags"][0]) + imageVulnCheck = str( + images["imageScanFindingsSummary"]["findingSeverityCounts"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if imageVulnCheck != "{}": + vulnDeepLink = ( + "https://console.aws.amazon.com/ecr/repositories/" + + repoName + + "/image/" + + imageDigest + + "/scan-results?region=" + + awsRegion + ) + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoName + + "/" + + imageDigest + + "/ecr-latest-image-vuln-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": imageDigest, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE", + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ECR.4] The latest image in an ECR Repository should not have any vulnerabilities", + "Description": "The latest image in the ECR repository " + + repoName + + " has the following vulnerabilities reported: " + + imageVulnCheck + + ". Refer to the SourceUrl or Remediation.Recommendation.Url to review the specific vulnerabilities and remediation information from ECR.", + "Remediation": { + "Recommendation": { + "Text": "Click here to navigate to the ECR Vulnerability console for this image", + "Url": vulnDeepLink, + } + }, + "SourceUrl": vulnDeepLink, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Container", + "Id": repoName + ":" + imageTag, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Container": { + "Name": repoName + ":" + imageTag, + "ImageId": imageDigest, + }, + "Other": { + "RepositoryName": repoName, + "RepositoryArn": repoArn, + }, + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.CM-8", + "NIST SP 800-53 RA-5", + "AICPA TSC CC7.1", + "ISO 27001:2013 A.12.6.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": repoName + + "/" + + imageDigest + + "/ecr-latest-image-vuln-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccount + + ":product/" + + awsAccount + + "/default", + "GeneratorId": imageDigest, + "AwsAccountId": awsAccount, + "Types": [ + "Software and Configuration Checks/Vulnerabilities/CVE", + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECR.4] The latest image in an ECR Repository should not have any vulnerabilities", + "Description": "The latest image in the ECR repository " + + repoName + + " does not have any vulnerabilities reported.", + "Remediation": { + "Recommendation": { + "Text": "Click here to navigate to the ECR Vulnerability console for this image", + "Url": vulnDeepLink, + } + }, + "SourceUrl": vulnDeepLink, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Container", + "Id": repoName + ":" + imageTag, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Container": { + "Name": repoName + ":" + imageTag, + "ImageId": imageDigest, + }, + "Other": { + "RepositoryName": repoName, + "RepositoryArn": repoArn, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.CM-8", + "NIST SP 800-53 RA-5", + "AICPA TSC CC7.1", + "ISO 27001:2013 A.12.6.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + else: + pass diff --git a/eeauditor/auditors/Amazon_ECS_Auditor.py b/eeauditor/auditors/Amazon_ECS_Auditor.py new file mode 100644 index 00000000..16dd49bd --- /dev/null +++ b/eeauditor/auditors/Amazon_ECS_Auditor.py @@ -0,0 +1,317 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +ecs = boto3.client("ecs") +securityhub = boto3.client("securityhub") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through ECS Clusters +response = ecs.list_clusters() +myEcsClusters = response["clusterArns"] + + +class EcsClusterContainerInsightsCheck(Auditor): + def execute(self): + for clusters in myEcsClusters: + clusterArn = str(clusters) + try: + response = ecs.describe_clusters(clusters=[clusterArn]) + for clusterinfo in response["clusters"]: + clusterName = str(clusterinfo["clusterName"]) + ecsClusterArn = str(clusterinfo["clusterArn"]) + for settings in clusterinfo["settings"]: + contInsightsCheck = str(settings["value"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if contInsightsCheck == "disabled": + finding = { + "SchemaVersion": "2018-10-08", + "Id": ecsClusterArn + + "/ecs-cluster-container-insights-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ecsClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ECS.1] ECS clusters should have container insights enabled", + "Description": "ECS cluster " + + clusterName + + " does not have container insights enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For information on configuring Container Insights for your cluster refer to the Setting Up Container Insights on Amazon ECS for Cluster- and Service-Level Metrics section of the Amazon CloudWatch User Guide", + "Url": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-ECS-cluster.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcsCluster", + "Id": ecsClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"ClusterName": clusterName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ecsClusterArn + + "/ecs-cluster-container-insights-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ecsClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECS.1] ECS clusters should have container insights enabled", + "Description": "ECS cluster " + + clusterName + + " has container insights enabled.", + "Remediation": { + "Recommendation": { + "Text": "For information on configuring Container Insights for your cluster refer to the Setting Up Container Insights on Amazon ECS for Cluster- and Service-Level Metrics section of the Amazon CloudWatch User Guide", + "Url": "https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-ECS-cluster.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcsCluster", + "Id": ecsClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"ClusterName": clusterName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class EcsClusterDefaultProviderStrategyCheck(Auditor): + def execute(self): + for clusters in myEcsClusters: + clusterArn = str(clusters) + try: + response = ecs.describe_clusters(clusters=[clusterArn]) + for clusterinfo in response["clusters"]: + clusterName = str(clusterinfo["clusterName"]) + ecsClusterArn = str(clusterinfo["clusterArn"]) + defaultProviderStratCheck = str( + clusterinfo["defaultCapacityProviderStrategy"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if defaultProviderStratCheck == "[]": + finding = { + "SchemaVersion": "2018-10-08", + "Id": ecsClusterArn + + "/ecs-cluster-default-provider-strategy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ecsClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECS.2] ECS clusters should have a default cluster capacity provider strategy configured", + "Description": "ECS cluster " + + clusterName + + " does not have a default provider strategy configured. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For information on cluster capacity provider strategies for your cluster refer to the Amazon ECS Cluster Capacity Providers section of the Amazon Elastic Container Service Developer Guide", + "Url": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcsCluster", + "Id": ecsClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ecsClusterArn + + "/ecs-cluster-default-provider-strategy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ecsClusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ECS.2] ECS clusters should have a default cluster capacity provider strategy configured", + "Description": "ECS cluster " + + clusterName + + " has a default provider strategy configured.", + "Remediation": { + "Recommendation": { + "Text": "For information on cluster capacity provider strategies for your cluster refer to the Amazon ECS Cluster Capacity Providers section of the Amazon Elastic Container Service Developer Guide", + "Url": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/cluster-capacity-providers.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEcsCluster", + "Id": ecsClusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_EFS_Auditor.py b/eeauditor/auditors/Amazon_EFS_Auditor.py new file mode 100644 index 00000000..8ea53b93 --- /dev/null +++ b/eeauditor/auditors/Amazon_EFS_Auditor.py @@ -0,0 +1,165 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +efs = boto3.client("efs") +sts = boto3.client("sts") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through EFS file systems +response = efs.describe_file_systems() +myFileSys = response["FileSystems"] + + +class EfsFilesysEncryptionCheck(Auditor): + def execute(self): + for filesys in myFileSys: + encryptionCheck = str(filesys["Encrypted"]) + fileSysId = str(filesys["FileSystemId"]) + fileSysArn = ( + "arn:aws:elasticfilesystem:" + + awsRegion + + ":" + + awsAccountId + + ":file-system/" + + fileSysId + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if encryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": fileSysArn + "/efs-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": fileSysArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EFS.1] EFS File Systems should have encryption enabled", + "Description": "EFS file system " + + fileSysId + + " does not have encryption enabled. EFS file systems cannot be encrypted after creation, consider backing up data and creating a new encrypted file system.", + "Remediation": { + "Recommendation": { + "Text": "For EFS encryption information refer to the Data Encryption in EFS section of the Amazon Elastic File System User Guide", + "Url": "https://docs.aws.amazon.com/efs/latest/ug/encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticFileSystem", + "Id": fileSysArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"fileSystemId": fileSysId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": fileSysArn + "/efs-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": fileSysArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EFS.1] EFS File Systems should have encryption enabled", + "Description": "EFS file system " + + fileSysId + + " has encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "For EFS encryption information refer to the Data Encryption in EFS section of the Amazon Elastic File System User Guide", + "Url": "https://docs.aws.amazon.com/efs/latest/ug/encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticFileSystem", + "Id": fileSysArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"fileSystemId": fileSysId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_EKS_Auditor.py b/eeauditor/auditors/Amazon_EKS_Auditor.py new file mode 100644 index 00000000..23f95674 --- /dev/null +++ b/eeauditor/auditors/Amazon_EKS_Auditor.py @@ -0,0 +1,469 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +eks = boto3.client("eks") +securityhub = boto3.client("securityhub") +# create region & account variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] + + +class EksPublicEndpointAccessCheck(Auditor): + def execute(self): + # loop through EKS clusters + response = eks.list_clusters(maxResults=100) + myEksClusters = response["clusters"] + for clusters in myEksClusters: + cluster = str(clusters) + try: + response = eks.describe_cluster(name=cluster) + clusterName = str(response["cluster"]["name"]) + clusterArn = str(response["cluster"]["arn"]) + eksPublicAccessCheck = str( + response["cluster"]["resourcesVpcConfig"]["endpointPublicAccess"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if eksPublicAccessCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/public-endpoint-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[EKS.1] Elastic Kubernetes Service (EKS) cluster API servers should not be accessible from the internet", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " API server is accessible from the internet. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your EKS cluster is not intended to be public refer to the Amazon EKS Cluster Endpoint Access Control section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"Cluster Name": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/public-endpoint-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EKS.1] Elastic Kubernetes Service (EKS) cluster API servers should not be accessible from the internet", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " API server is not accessible from the internet.", + "Remediation": { + "Recommendation": { + "Text": "If your EKS cluster is not intended to be public refer to the Amazon EKS Cluster Endpoint Access Control section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"Cluster Name": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class EksLatestK8sVersionCheck(Auditor): + def execute(self): + # loop through EKS clusters + response = eks.list_clusters(maxResults=100) + myEksClusters = response["clusters"] + for clusters in myEksClusters: + cluster = str(clusters) + try: + response = eks.describe_cluster(name=cluster) + clusterName = str(response["cluster"]["name"]) + clusterArn = str(response["cluster"]["arn"]) + k8sVersionCheck = str(response["cluster"]["version"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if k8sVersionCheck != "1.14" or "1.15": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/eks-latest-k8s-version-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EKS.2] Elastic Kubernetes Service (EKS) clusters should use the latest Kubernetes version", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " is using Kubernetes version " + + k8sVersionCheck + + ". Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "Unless your application requires a specific version of Kubernetes, AWS recommends you choose the latest available Kubernetes version supported by Amazon EKS for your clusters. For upgrade information refer to the Updating an Amazon EKS Cluster Kubernetes Version section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"Cluster Name": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/eks-latest-k8s-version-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EKS.2] Elastic Kubernetes Service (EKS) clusters should use the latest Kubernetes version", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " is using Kubernetes version " + + k8sVersionCheck, + "Remediation": { + "Recommendation": { + "Text": "Unless your application requires a specific version of Kubernetes, AWS recommends you choose the latest available Kubernetes version supported by Amazon EKS for your clusters. For upgrade information refer to the Updating an Amazon EKS Cluster Kubernetes Version section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"Cluster Name": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class EksLoggingAuditAuthCheck(Auditor): + def execute(self): + # loop through EKS clusters + response = eks.list_clusters(maxResults=100) + myEksClusters = response["clusters"] + for clusters in myEksClusters: + cluster = str(clusters) + try: + response = eks.describe_cluster(name=cluster) + clusterName = str(response["cluster"]["name"]) + clusterArn = str(response["cluster"]["arn"]) + logInfo = response["cluster"]["logging"]["clusterLogging"] + for logs in logInfo: + logTypes = logs["types"] + enableCheck = str(logs["enabled"]) + if enableCheck == "True": + for logs in logTypes: + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if str(logs) == "authenticator" and "audit": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/eks-logging-audit-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EKS.3] Elastic Kubernetes Service (EKS) clusters should have authenticator and/or audit logging enabled", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " has authenticator and audit logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "To enable logging for your cluster refer to the Amazon EKS Control Plane Logging section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"Cluster Name": clusterName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/eks-logging-audit-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterName, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EKS.3] Elastic Kubernetes Service (EKS) clusters should have authenticator and/or audit logging enabled", + "Description": "Elastic Kubernetes Service (EKS) cluster " + + clusterName + + " does not have authenticator or audit logging enabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "To enable logging for your cluster refer to the Amazon EKS Control Plane Logging section of the EKS user guide", + "Url": "https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEksCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"Cluster Name": clusterName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_ELB_Auditor.py b/eeauditor/auditors/Amazon_ELB_Auditor.py new file mode 100644 index 00000000..61a88699 --- /dev/null +++ b/eeauditor/auditors/Amazon_ELB_Auditor.py @@ -0,0 +1,769 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# create boto3 clients +sts = boto3.client("sts") +elb = boto3.client("elb") +securityhub = boto3.client("securityhub") +# creat env vars +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] + + +class InternetFacingClbHttpsListenerCheck(Auditor): + def execute(self): + # loop through classic load balancers + response = elb.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + clbScheme = str(classicbalancer["Scheme"]) + if clbScheme == "internet-facing": + for listeners in classicbalancer["ListenerDescriptions"]: + listenerProtocol = str(listeners["Listener"]["Protocol"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if listenerProtocol != "HTTPS" or "SSL": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + + "/classic-loadbalancer-secure-listener-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ELB.1] Classic load balancers that are internet-facing should use secure listeners", + "Description": "Classic load balancer " + + clbName + + " does not use a secure listener (HTTPS or SSL). Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on classic load balancer HTTPS listeners refer to the Create a Classic Load Balancer with an HTTPS Listener section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-create-https-ssl-load-balancer.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + + "/classic-loadbalancer-secure-listener-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELB.1] Classic load balancers that are internet-facing should use secure listeners", + "Description": "Classic load balancer " + + clbName + + " uses a secure listener (HTTPS or SSL).", + "Remediation": { + "Recommendation": { + "Text": "For more information on classic load balancer HTTPS listeners refer to the Create a Classic Load Balancer with an HTTPS Listener section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-create-https-ssl-load-balancer.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + print("Ignoring internal CLB") + pass + + +class ClbHttpsListenerTls12PolicyCheck(Auditor): + def execute(self): + # loop through classic load balancers + response = elb.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + for listeners in classicbalancer["ListenerDescriptions"]: + listenerPolicies = str(listeners["PolicyNames"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if listenerPolicies == "[]": + pass + elif listenerPolicies == "ELBSecurityPolicy-TLS-1-2-2017-01": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-tls12-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELB.2] Classic load balancers should use TLS 1.2 listener policies", + "Description": "Classic load balancer " + + clbName + + " does not use a TLS 1.2 listener policy.", + "Remediation": { + "Recommendation": { + "Text": "For more information on classic load balancer listener policies refer to the Predefined SSL Security Policies for Classic Load Balancers section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-tls12-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ELB.2] Classic load balancers should use TLS 1.2 listener policies", + "Description": "Classic load balancer " + + clbName + + " does not use a TLS 1.2 listener policy. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on classic load balancer listener policies refer to the Predefined SSL Security Policies for Classic Load Balancers section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class ClbCrossZoneBalancingCheck(Auditor): + def execute(self): + # loop through classic load balancers + response = elb.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) + crossZoneCheck = str( + response["LoadBalancerAttributes"]["CrossZoneLoadBalancing"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if crossZoneCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-cross-zone-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ELB.3] Classic load balancers should have cross-zone load balancing configured", + "Description": "Classic load balancer " + + clbName + + " does not have cross-zone load balancing configured. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on cross-zone load balancing refer to the Configure Cross-Zone Load Balancing for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-cross-zone-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELB.3] Classic load balancers should have cross-zone load balancing configured", + "Description": "Classic load balancer " + + clbName + + " has cross-zone load balancing configured.", + "Remediation": { + "Recommendation": { + "Text": "For more information on cross-zone load balancing refer to the Configure Cross-Zone Load Balancing for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/enable-disable-crosszone-lb.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class ClbConnectionDrainingCheck(Auditor): + def execute(self): + # loop through classic load balancers + response = elb.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) + connectionDrainCheck = str( + response["LoadBalancerAttributes"]["ConnectionDraining"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if connectionDrainCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-connection-draining-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ELB.4] Classic load balancers should have connection draining configured", + "Description": "Classic load balancer " + + clbName + + " does not have connection draining configured. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on connection draining refer to the Configure Connection Draining for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-conn-drain.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-connection-draining-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELB.4] Classic load balancers should have connection draining configured", + "Description": "Classic load balancer " + + clbName + + " does not have connection draining configured.", + "Remediation": { + "Recommendation": { + "Text": "For more information on connection draining refer to the Configure Connection Draining for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-conn-drain.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class ClbAccessLoggingCheck(Auditor): + def execute(self): + # loop through classic load balancers + response = elb.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + response = elb.describe_load_balancer_attributes(LoadBalancerName=clbName) + accessLogCheck = str( + response["LoadBalancerAttributes"]["AccessLog"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if accessLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-access-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ELB.5] Classic load balancers should enable access logging", + "Description": "Classic load balancer " + + clbName + + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on access logging refer to the Access Logs for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classic-loadbalancer-access-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELB.5] Classic load balancers should enable access logging", + "Description": "Classic load balancer " + + clbName + + " does not have access logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on access logging refer to the Access Logs for Your Classic Load Balancer section of the Classic Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/access-log-collection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_ELBv2_Auditor.py b/eeauditor/auditors/Amazon_ELBv2_Auditor.py new file mode 100644 index 00000000..0835cd05 --- /dev/null +++ b/eeauditor/auditors/Amazon_ELBv2_Auditor.py @@ -0,0 +1,1072 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +elbv2 = boto3.client("elbv2") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through ELBv2 load balancers +response = elbv2.describe_load_balancers() +myElbv2LoadBalancers = response["LoadBalancers"] + + +class Elbv2AlbLoggingCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + if elbv2LbType == "application": + try: + response = elbv2.describe_load_balancer_attributes( + LoadBalancerArn=elbv2Arn + ) + elbv2Attributes = response["Attributes"] + for attributes in elbv2Attributes: + if str(attributes["Key"]) == "access_logs.s3.enabled": + elbv2LoggingCheck = str(attributes["Value"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if elbv2LoggingCheck == "false": + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ELBv2.1] Application Load Balancers should have access logging enabled", + "Description": "Application load balancer " + + elbv2Name + + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Access Logs for Your Application Load Balancer section of the Application Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.1] Application and Network Load Balancers should have access logging enabled", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " has access logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Access Logs for Your Application Load Balancer section of the Application Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-access-logs.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + except Exception as e: + print(e) + else: + pass + + +class Elbv2DeletionProtectionCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + try: + response = elbv2.describe_load_balancer_attributes( + LoadBalancerArn=elbv2Arn + ) + elbv2Attributes = response["Attributes"] + for attributes in elbv2Attributes: + if str(attributes["Key"]) == "deletion_protection.enabled": + elbv2LoggingCheck = str(attributes["Value"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if elbv2LoggingCheck == "false": + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-deletion-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ELBv2.2] Application and Network Load Balancers should have deletion protection enabled", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " does not have deletion protection enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Deletion Protection section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-deletion-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.2] Application and Network Load Balancers should have deletion protection enabled", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " has deletion protection enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Deletion Protection section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#deletion-protection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + except Exception as e: + print(e) + + +class Elbv2InternetFacingSecureListenersCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + try: + response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) + myElbv2Listeners = response["Listeners"] + for listeners in myElbv2Listeners: + listenerProtocol = str(listeners["Protocol"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + elbv2Scheme == "internet-facing" + and listenerProtocol != "HTTPS" + or "TLS" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/internet-facing-secure-listeners-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[ELBv2.3] Internet-facing Application and Network Load Balancers should have secure listeners configured", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " does not have a secure listener configured. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Create an HTTPS Listener for Your Application Load Balancer section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/internet-facing-secure-listeners-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.3] Internet-facing Application and Network Load Balancers should have secure listeners configured", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " has a secure listener configured.", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Create an HTTPS Listener for Your Application Load Balancer section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class Elbv2Tls12ListenerPolicyCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + try: + response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) + myElbv2Listeners = response["Listeners"] + for listeners in myElbv2Listeners: + listenerProtocol = str(listeners["Protocol"]) + if listenerProtocol == "HTTPS" or "TLS": + listenerTlsPolicyCheck = str(listeners["SslPolicy"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + listenerTlsPolicyCheck + != "ELBSecurityPolicy-TLS-1-2-2017-01" + or "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" + or "ELBSecurityPolicy-FS-1-2-2019-08" + or "ELBSecurityPolicy-FS-1-2-Res-2019-08" + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/secure-listener-tls12-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[ELBv2.4] Application and Network Load Balancers with HTTPS or TLS listeners should enforce TLS 1.2 policies", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " does not enforce a TLS 1.2 policy. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Security Policies section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/secure-listener-tls12-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.4] Application and Network Load Balancers with HTTPS or TLS listeners should enforce TLS 1.2 policies", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " enforces a TLS 1.2 policy.", + "Remediation": { + "Recommendation": { + "Text": "For more information on ELBv2 Access Logging and how to configure it refer to the Security Policies section of the Application Load Balancers User Guide. For Network Load Balancer logging please refer to the NLB User Guide", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + except Exception as e: + print(e) + + +class Elbv2DropInvalidHeaderCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + response = elbv2.describe_load_balancer_attributes(LoadBalancerArn=elbv2Arn) + elbv2Attributes = response["Attributes"] + for attributes in elbv2Attributes: + if ( + str(attributes["Key"]) + == "routing.http.drop_invalid_header_fields.enabled" + ): + elbv2DropInvalidHeaderCheck = str(attributes["Value"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if elbv2DropInvalidHeaderCheck == "false": + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-drop-invalid-header-fields-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ELBv2.5] Application Load Balancers should drop invalid HTTP header fields", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " does not drop invalid HTTP header fields. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on dropping invalid HTTP headers refer to the routing.http.drop_invalid_header_fields.enabled section of the Application Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#load-balancer-attributes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-drop-invalid-header-fields-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.5] Application Load Balancers should drop invalid HTTP header fields", + "Description": "ELB " + + elbv2LbType + + " load balancer " + + elbv2Name + + " drops invalid HTTP header fields.", + "Remediation": { + "Recommendation": { + "Text": "For more information on dropping invalid HTTP headers refer to the routing.http.drop_invalid_header_fields.enabled section of the Application Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html#load-balancer-attributes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + }, + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class Elbv2NlbTlsLoggingCheck(Auditor): + def execute(self): + for loadbalancers in myElbv2LoadBalancers: + elbv2Arn = str(loadbalancers["LoadBalancerArn"]) + elbv2Name = str(loadbalancers["LoadBalancerName"]) + elbv2DnsName = str(loadbalancers["DNSName"]) + elbv2LbType = str(loadbalancers["Type"]) + elbv2Scheme = str(loadbalancers["Scheme"]) + elbv2VpcId = str(loadbalancers["VpcId"]) + elbv2IpAddressType = str(loadbalancers["IpAddressType"]) + if elbv2LbType == "network": + try: + response = elbv2.describe_listeners(LoadBalancerArn=elbv2Arn) + for listeners in response["Listeners"]: + protocolCheck = str(listeners["Protocol"]) + if protocolCheck == "TLS": + try: + response = elbv2.describe_load_balancer_attributes( + LoadBalancerArn=elbv2Arn + ) + elbv2Attributes = response["Attributes"] + for attributes in elbv2Attributes: + if ( + str(attributes["Key"]) + == "access_logs.s3.enabled" + ): + elbv2LoggingCheck = str(attributes["Value"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if elbv2LoggingCheck == "false": + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + + "/tls-nlb-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ELBv2.6] Network Load Balancers with TLS listeners should have access logging enabled", + "Description": "Network load balancer " + + elbv2Name + + " does not have access logging enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on Network Load Balancer Access Logging and how to configure it refer to the Access Logs for Your Network Load Balancer section of the Network Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + + "/tls-nlb-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ELBv2.6] Network Load Balancers with TLS listeners should have access logging enabled", + "Description": "Network load balancer " + + elbv2Name + + " has access logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Network Load Balancer Access Logging and how to configure it refer to the Access Logs for Your Network Load Balancer section of the Network Load Balancers User Guide.", + "Url": "https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-access-logs.html", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + except Exception as e: + print(e) + else: + pass + except Exception as e: + print(e) + else: + pass diff --git a/eeauditor/auditors/Amazon_EMR_Auditor.py b/eeauditor/auditors/Amazon_EMR_Auditor.py new file mode 100644 index 00000000..6a066b54 --- /dev/null +++ b/eeauditor/auditors/Amazon_EMR_Auditor.py @@ -0,0 +1,1400 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import json +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +emr = boto3.client("emr") +sts = boto3.client("sts") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through non-terminated EMR clusters +try: + response = emr.list_clusters(ClusterStates=["STARTING", "RUNNING", "WAITING"]) + myEmrClusters = response["Clusters"] +except Exception as e: + print(e) + + +class EmrClusterSecurityConfigurationCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + secConfigName = str(response["Cluster"]["SecurityConfiguration"]) + # this is a Passing Check + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-cluster-sec-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.1] EMR Clusters should have a security configuration specified", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on creating and attaching a security configuration refer to the Use Security Configurations to Set Up Cluster Security section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-security-configurations.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.IP-1", + "NIST SP 800-53 CM-2", + "NIST SP 800-53 CM-3", + "NIST SP 800-53 CM-4", + "NIST SP 800-53 CM-5", + "NIST SP 800-53 CM-6", + "NIST SP 800-53 CM-7", + "NIST SP 800-53 CM-9", + "NIST SP 800-53 SA-10", + "AICPA TSC A1.3", + "AICPA TSC CC1.4", + "AICPA TSC CC5.3", + "AICPA TSC CC6.2", + "AICPA TSC CC7.1", + "AICPA TSC CC7.3", + "AICPA TSC CC7.4", + "ISO 27001:2013 A.12.1.2", + "ISO 27001:2013 A.12.5.1", + "ISO 27001:2013 A.12.6.2", + "ISO 27001:2013 A.14.2.2", + "ISO 27001:2013 A.14.2.3", + "ISO 27001:2013 A.14.2.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if str(e) == "'SecurityConfiguration'": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-cluster-sec-policy-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EMR.1] EMR Clusters should have a security configuration specified", + "Description": "EMR Cluster " + + clusterName + + " does not have a security configuration specified. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on creating and attaching a security configuration refer to the Use Security Configurations to Set Up Cluster Security section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-security-configurations.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.IP-1", + "NIST SP 800-53 CM-2", + "NIST SP 800-53 CM-3", + "NIST SP 800-53 CM-4", + "NIST SP 800-53 CM-5", + "NIST SP 800-53 CM-6", + "NIST SP 800-53 CM-7", + "NIST SP 800-53 CM-9", + "NIST SP 800-53 SA-10", + "AICPA TSC A1.3", + "AICPA TSC CC1.4", + "AICPA TSC CC5.3", + "AICPA TSC CC6.2", + "AICPA TSC CC7.1", + "AICPA TSC CC7.3", + "AICPA TSC CC7.4", + "ISO 27001:2013 A.12.1.2", + "ISO 27001:2013 A.12.5.1", + "ISO 27001:2013 A.12.6.2", + "ISO 27001:2013 A.14.2.2", + "ISO 27001:2013 A.14.2.3", + "ISO 27001:2013 A.14.2.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + +class EmrSecurityConfigEncryptionInTransitCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + secConfigName = str(response["Cluster"]["SecurityConfiguration"]) + try: + response = emr.describe_security_configuration(Name=secConfigName) + configData = str(response["SecurityConfiguration"]) + jsonConfig = json.loads(configData) + try: + eitCheck = str( + jsonConfig["EncryptionConfiguration"][ + "EnableInTransitEncryption" + ] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if eitCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-encryption-in-transit-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EMR.2] EMR Cluster security configurations should enforce encryption in transit", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enforce encryption in transit. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption in transit refer to the Encryption in Transit section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-intransit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-encryption-in-transit-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.2] EMR Cluster security configurations should enforce encryption in transit", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that enforces encryption in transit.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption in transit refer to the Encryption in Transit section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-intransit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + except Exception as e: + if str(e) == "'SecurityConfiguration'": + pass + else: + print(e) + + +class EmrSecurityConfigEncryptionAtRestCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + secConfigName = str(response["Cluster"]["SecurityConfiguration"]) + try: + response = emr.describe_security_configuration(Name=secConfigName) + configData = str(response["SecurityConfiguration"]) + jsonConfig = json.loads(configData) + try: + earCheck = str( + jsonConfig["EncryptionConfiguration"][ + "EnableAtRestEncryption" + ] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if earCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + + "/emr-encryption-at-rest-emrfs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EMR.3] EMR Cluster security configurations should enforce encryption at rest for EMRFS", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enforce encryption at rest for EMRFS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EMRFS refer to the Encryption at Rest for EMRFS Data in Amazon S3 section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-s3", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + + "/emr-encryption-at-rest-emrfs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.3] EMR Cluster security configurations should enforce encryption at rest for EMRFS", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enforce encryption at rest for EMRFS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EMRFS refer to the Encryption at Rest for EMRFS Data in Amazon S3 section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-s3", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + except Exception as e: + if str(e) == "'SecurityConfiguration'": + pass + else: + print(e) + + +class EmrSecurityConfigConfigEbsEncryptionCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + secConfigName = str(response["Cluster"]["SecurityConfiguration"]) + try: + response = emr.describe_security_configuration(Name=secConfigName) + configData = str(response["SecurityConfiguration"]) + jsonConfig = json.loads(configData) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + ebsEncryptionCheck = str( + jsonConfig["EncryptionConfiguration"][ + "AtRestEncryptionConfiguration" + ]["LocalDiskEncryptionConfiguration"]["EnableEbsEncryption"] + ) + if ebsEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enforce encryption at rest for EBS. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that enforces encryption at rest for EBS.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if str(e) == "'LocalDiskEncryptionConfiguration'": + # this is a failing check of a lesser severity + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-encryption-at-rest-ebs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EMR.4] EMR Cluster security configurations should enforce encryption at rest for EBS", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration that does not have any local disk encryption configured. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on encryption at rest for EBS refer to the Local Disk Encryption section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html#emr-encryption-localdisk", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + except Exception as e: + print(e) + except Exception as e: + if str(e) == "'SecurityConfiguration'": + pass + else: + print(e) + + +class EmrSecurityConfigKerberosCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + secConfigName = str(response["Cluster"]["SecurityConfiguration"]) + try: + response = emr.describe_security_configuration(Name=secConfigName) + configData = str(response["SecurityConfiguration"]) + jsonConfig = json.loads(configData) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + kerbCheck = str(jsonConfig["AuthenticationConfiguration"]) + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-kerberos-authn-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.5] EMR Cluster security configurations should enable Kerberos authentication", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enable Kerberos authentication. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on Kerberized EMR clusters refer to the Use Kerberos Authentication section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-kerberos.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + "authenticationConfiguration": kerbCheck, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if str(e) == "'AuthenticationConfiguration'": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-kerberos-authn-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EMR.5] EMR Cluster security configurations should enable Kerberos authentication", + "Description": "EMR Cluster " + + clusterName + + " has a security configuration specified that does not enable Kerberos authentication. Security configurations are used to define encryption, authorization and authentication strategies for your EMR cluster. Clusters cannot be modified after creation, for more information refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "EMR cluster security configurations cannot be specified after creation. For information on Kerberized EMR clusters refer to the Use Kerberos Authentication section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-kerberos.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "securityConfigurationName": secConfigName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + except Exception as e: + print(e) + except Exception as e: + if str(e) == "'SecurityConfiguration'": + pass + else: + print(e) + + +class EmrClusterTerminationProtectionCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + delProtectCheck = str(response["Cluster"]["TerminationProtected"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if delProtectCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-termination-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EMR.6] EMR Clusters should have termination protection enabled", + "Description": "EMR Cluster " + + clusterName + + " does not have termination protection enabled. When termination protection is enabled on a long-running cluster, you can still terminate the cluster, but you must explicitly remove termination protection from the cluster first. This helps ensure that EC2 instances are not shut down by an accident or error. If this configuration is not intentional refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR termination protection refer to the Using Termination Protection section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/UsingEMR_TerminationProtection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-termination-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.6] EMR Clusters should have termination protection enabled", + "Description": "EMR Cluster " + + clusterName + + " has termination protection enabled.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR termination protection refer to the Using Termination Protection section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/UsingEMR_TerminationProtection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class EmrClusterLoggingCheck(Auditor): + def execute(self): + for cluster in myEmrClusters: + clusterId = str(cluster["Id"]) + try: + response = emr.describe_cluster(ClusterId=clusterId) + clusterId = str(response["Cluster"]["Id"]) + clusterName = str(response["Cluster"]["Name"]) + clusterArn = str(response["Cluster"]["ClusterArn"]) + logUriCheck = str(response["Cluster"]["LogUri"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-cluster-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.7] EMR Clusters should have logging enabled", + "Description": "EMR Cluster " + + clusterName + + " does has logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR cluster logging and debugging refer to the Configure Cluster Logging and Debugging section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-debugging.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + "logPathUri": logUriCheck, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if str(e) == "'LogUri'": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/emr-cluster-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[EMR.7] EMR Clusters should have logging enabled", + "Description": "EMR Cluster " + + clusterName + + " does not have logging enabled. You do not need to enable anything to have log files written on the master node. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR cluster logging and debugging refer to the Configure Cluster Logging and Debugging section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-debugging.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEmrCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "clusterId": clusterId, + "clusterName": clusterName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + +class EmrClusterBlockSecgroupCheck(Auditor): + def execute(self): + try: + response = emr.get_block_public_access_configuration() + blockPubSgCheck = str( + response["BlockPublicAccessConfiguration"][ + "BlockPublicSecurityGroupRules" + ] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if blockPubSgCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/account-level-emr-block-public-sg-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId + + "/" + + awsRegion + + "/" + + "emr-acct-sg-block", + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[EMR.8] EMR account-level public security group access block should be enabled", + "Description": "EMR account-level public security group access block is not enabled for " + + awsAccountId + + " in AWS region " + + awsRegion + + ". Amazon EMR block public access prevents a cluster from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception. Port 22 is an exception by default. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR Block Public Access refer to the Using Amazon EMR Block Public Access section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-block-public-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/account-level-emr-block-public-sg-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId + + "/" + + awsRegion + + "/" + + "emr-acct-sg-block", + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[EMR.8] EMR account-level public security group access block should be enabled", + "Description": "EMR account-level public security group access block is not enabled for " + + awsAccountId + + " in AWS region " + + awsRegion + + ". Amazon EMR block public access prevents a cluster from launching when any security group associated with the cluster has a rule that allows inbound traffic from IPv4 0.0.0.0/0 or IPv6 ::/0 (public access) on a port, unless the port has been specified as an exception. Port 22 is an exception by default. This is the default behavior of Amazon EMR and Hadoop, but can be turned off on creation. If this configuration is not intentional refer to the remediation section.", + "Remediation": { + "Recommendation": { + "Text": "For information on EMR Block Public Access refer to the Using Amazon EMR Block Public Access section of the Amazon EMR Management Guide", + "Url": "https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-block-public-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_Elasticache_Redis_Auditor.py b/eeauditor/auditors/Amazon_Elasticache_Redis_Auditor.py new file mode 100644 index 00000000..5eaab5f1 --- /dev/null +++ b/eeauditor/auditors/Amazon_Elasticache_Redis_Auditor.py @@ -0,0 +1,536 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +elasticache = boto3.client("elasticache") +securityhub = boto3.client("securityhub") +# create env vars for account and region +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] + + +class RedisAuthCheck(Auditor): + def execute(self): + # loop through EC clusters + response = elasticache.describe_cache_clusters(MaxRecords=100) + myElasticacheClusters = response["CacheClusters"] + for clusters in myElasticacheClusters: + clusterId = str(clusters["CacheClusterId"]) + clusterEngine = str(clusters["Engine"]) + # ignore memcached clusters + if clusterEngine != "redis": + pass + else: + engineVersion = str(clusters["EngineVersion"]) + # check for auth token + authTokenCheck = str(clusters["AuthTokenEnabled"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if authTokenCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.1] Elasticache Redis clusters should have an AUTH token enabled", + "Description": "Elasticache cluster " + + clusterId + + " does not have a Redis AUTH token enabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have a Redis AUTH token refer to the Modifying the AUTH Token on an Existing ElastiCache for Redis Cluster section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html#auth-modifyng-token", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.1] Elasticache Redis clusters should have an AUTH token enabled", + "Description": "Elasticache cluster " + + clusterId + + " has a Redis AUTH token enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have a Redis AUTH token refer to the Modifying the AUTH Token on an Existing ElastiCache for Redis Cluster section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html#auth-modifyng-token", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EncryptionAtRestCheck(Auditor): + def execute(self): + # loop through EC clusters + response = elasticache.describe_cache_clusters(MaxRecords=100) + myElasticacheClusters = response["CacheClusters"] + for clusters in myElasticacheClusters: + clusterId = str(clusters["CacheClusterId"]) + clusterEngine = str(clusters["Engine"]) + # ignore memcached clusters + if clusterEngine != "redis": + print( + "Memcached cluster found, skipping as it does not support encryption" + ) + pass + else: + engineVersion = str(clusters["EngineVersion"]) + # check for encryption at rest + atRestEncryptionCheck = str(clusters["AtRestEncryptionEnabled"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if atRestEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.2] Elasticache Redis clusters should have encryption at rest enabled", + "Description": "Elasticache cluster " + + clusterId + + " does not have encryption at rest enabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have encryption at rest enabled refer to the At-Rest Encryption in ElastiCache for Redis section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/at-rest-encryption.html#at-rest-encryption-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.2] Elasticache Redis clusters should have encryption at rest enabled", + "Description": "Elasticache cluster " + + clusterId + + " has encryption at rest enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have encryption at rest enabled refer to the At-Rest Encryption in ElastiCache for Redis section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/at-rest-encryption.html#at-rest-encryption-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EncryptionInTransitCheck(Auditor): + def execute(self): + # loop through EC clusters + response = elasticache.describe_cache_clusters(MaxRecords=100) + myElasticacheClusters = response["CacheClusters"] + for clusters in myElasticacheClusters: + clusterId = str(clusters["CacheClusterId"]) + clusterEngine = str(clusters["Engine"]) + # ignore memcached clusters + if clusterEngine != "redis": + print( + "Memcached cluster found, skipping as it does not support encryption" + ) + pass + else: + engineVersion = str(clusters["EngineVersion"]) + # check for encryption in transit + inTransitEncryptionCheck = str(clusters["TransitEncryptionEnabled"]) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if inTransitEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.3] Elasticache Redis clusters should have encryption in transit enabled", + "Description": "Elasticache cluster " + + clusterId + + " does not have encryption in transit enabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have encryption in transit enabled refer to the Enabling In-Transit Encryption section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#in-transit-encryption-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterId + "/no-redis-auth-token", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticache.Redis.3] Elasticache Redis clusters should have encryption in transit enabled", + "Description": "Elasticache cluster " + + clusterId + + " has encryption in transit enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have encryption in transit enabled refer to the Enabling In-Transit Encryption section of the ElastiCache for Redis User Guide", + "Url": "https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/in-transit-encryption.html#in-transit-encryption-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElastiCacheCacheCluster", + "Id": "arn:aws:elasticache:" + + awsRegion + + ":" + + awsAccountId + + ":cluster:" + + clusterId, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ClusterId": clusterId, + "EngineVersion": engineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_ElasticsearchService_Auditor.py b/eeauditor/auditors/Amazon_ElasticsearchService_Auditor.py new file mode 100644 index 00000000..549e8608 --- /dev/null +++ b/eeauditor/auditors/Amazon_ElasticsearchService_Auditor.py @@ -0,0 +1,1157 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +elasticsearch = boto3.client("es") +securityhub = boto3.client("securityhub") +# create env vars for account and region +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through elasticsearch domains +response = elasticsearch.list_domain_names() +myDomainNames = response["DomainNames"] + + +class DedicatedMasterCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + dedicatedMasterCheck = str( + response["DomainStatus"]["ElasticsearchClusterConfig"][ + "DedicatedMasterEnabled" + ] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if dedicatedMasterCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-dedicated-master-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[Elasticsearch.1] Elasticsearch Service domains should use dedicated master nodes", + "Description": "Elasticsearch Service domain " + + esDomainName + + " does not use dedicated master nodes. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your domain should dedicated master nodes enabled refer to the Configuring Amazon ES Domains section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains-configure-cluster", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-dedicated-master-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.1] Elasticsearch Service domains should use dedicated master nodes", + "Description": "Elasticsearch Service domain " + + esDomainName + + " uses dedicated master nodes.", + "Remediation": { + "Recommendation": { + "Text": "If your domain should dedicated master nodes enabled refer to the Configuring Amazon ES Domains section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomains-configure-cluster", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class CognitoCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + cognitoEnabledCheck = str( + response["DomainStatus"]["CognitoOptions"]["Enabled"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if cognitoEnabledCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-cognito-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Elasticsearch.2] Elasticsearch Service domains should use Cognito authentication for Kibana", + "Description": "Elasticsearch Service domain " + + esDomainName + + " does not use Cognito authentication for Kibana. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your domain should use Cognito authentication for Kibana refer to the Amazon Cognito Authentication for Kibana section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-cognito-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.2] Elasticsearch Service domains should use Cognito authentication for Kibana", + "Description": "Elasticsearch Service domain " + + esDomainName + + " uses Cognito authentication for Kibana.", + "Remediation": { + "Recommendation": { + "Text": "If your domain should use Cognito authentication for Kibana refer to the Amazon Cognito Authentication for Kibana section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-cognito-auth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class EncryptionAtRestCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + encryptionAtRestCheck = str( + response["DomainStatus"]["EncryptionAtRestOptions"]["Enabled"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if encryptionAtRestCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-encryption-at-rest-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticsearch.3] Elasticsearch Service domains should be encrypted at rest", + "Description": "Elasticsearch Service domain " + + esDomainName + + " is not encrypted at rest. You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later", + "Remediation": { + "Recommendation": { + "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later.", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html#enabling-ear", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "EncryptionAtRestOptions": {"Enabled": False}, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-encryption-at-rest-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.3] Elasticsearch Service domains should be encrypted at rest", + "Description": "Elasticsearch Service domain " + + esDomainName + + " is encrypted at rest", + "Remediation": { + "Recommendation": { + "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 5.1 or later.", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/encryption-at-rest.html#enabling-ear", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "EncryptionAtRestOptions": {"Enabled": True}, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class Node2nodeEncryptionCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + node2nodeEncryptionCheck = str( + response["DomainStatus"]["NodeToNodeEncryptionOptions"]["Enabled"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if node2nodeEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-node2node-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticsearch.4] Elasticsearch Service domains should use node-to-node encryption", + "Description": "Elasticsearch Service domain " + + esDomainName + + " does not use node-to-node encryption. You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later", + "Remediation": { + "Recommendation": { + "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later.", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ntn.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "NodeToNodeEncryptionOptions": {"Enabled": False}, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-node2node-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.4] Elasticsearch Service domains should use node-to-node encryption", + "Description": "Elasticsearch Service domain " + + esDomainName + + " uses node-to-node encryption.", + "Remediation": { + "Recommendation": { + "Text": "You cannot configure existing domains to use the feature. To enable the feature, you must create another domain and migrate your data. Encryption of data at rest requires Elasticsearch 6.0 or later.", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/ntn.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "NodeToNodeEncryptionOptions": {"Enabled": True}, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class HttpsEnforcementCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + httpsEnforcementCheck = str( + response["DomainStatus"]["DomainEndpointOptions"]["EnforceHTTPS"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if httpsEnforcementCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-enforce-https-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticsearch.5] Elasticsearch Service domains should enforce HTTPS-only communications", + "Description": "Elasticsearch Service domain " + + esDomainName + + " does not enforce HTTPS-only communications. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your domain should enforce HTTPS-only communications refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "DomainEndpointOptions": {"EnforceHTTPS": False}, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-enforce-https-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.5] Elasticsearch Service domains should enforce HTTPS-only communications", + "Description": "Elasticsearch Service domain " + + esDomainName + + " enforces HTTPS-only communications. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your domain should enforce HTTPS-only communications refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "DomainEndpointOptions": {"EnforceHTTPS": True}, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class TlsPolicyCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + httpsEnforcementCheck = str( + response["DomainStatus"]["DomainEndpointOptions"]["EnforceHTTPS"] + ) + if httpsEnforcementCheck == "True": + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + tlsPolicyCheck = str( + response["DomainStatus"]["DomainEndpointOptions"][ + "TLSSecurityPolicy" + ] + ) + if tlsPolicyCheck != "Policy-Min-TLS-1-2-2019-07": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-tls-1-2-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Elasticsearch.6] Elasticsearch Service domains that enforce HTTPS-only communications should use a TLS 1.2 security policy", + "Description": "Elasticsearch Service domain " + + esDomainName + + " does not use a TLS 1.2 security policy. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your domain should use a TLS 1.2 security policy refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "DomainEndpointOptions": { + "EnforceHTTPS": True, + "TLSSecurityPolicy": tlsPolicyCheck, + }, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-tls-1-2-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.6] Elasticsearch Service domains that enforce HTTPS-only communications should use a TLS 1.2 security policy", + "Description": "Elasticsearch Service domain " + + esDomainName + + " uses a TLS 1.2 security policy.", + "Remediation": { + "Recommendation": { + "Text": "If your domain should use a TLS 1.2 security policy refer to the About Configuration Changes section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-managedomains-configuration-changes", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "DomainEndpointOptions": { + "EnforceHTTPS": True, + "TLSSecurityPolicy": tlsPolicyCheck, + }, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class ElasticUpdateCheck(Auditor): + def execute(self): + for domains in myDomainNames: + esDomainName = str(domains["DomainName"]) + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomainName + ) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + domainId = str(response["DomainStatus"]["DomainId"]) + domainArn = str(response["DomainStatus"]["ARN"]) + updateCheck = str( + response["DomainStatus"]["ServiceSoftwareOptions"]["UpdateAvailable"] + ) + updateInformation = str( + response["DomainStatus"]["ServiceSoftwareOptions"]["Description"] + ) + # ISO Time + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if updateCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-enforce-https-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[Elasticsearch.7] Elasticsearch Service domains should be updated to the latest service software version", + "Description": "Elasticsearch Service domain " + + esDomainName + + " is not up to date. Service provided message follows: " + + updateInformation + + ". Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For update information refer to the Service Software Updates section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-service-software", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.MA-1", + "NIST SP 800-53 MA-2", + "NIST SP 800-53 MA-3", + "NIST SP 800-53 MA-5", + "NIST SP 800-53 MA-6", + "AICPA TSC CC8.1", + "ISO 27001:2013 A.11.1.2", + "ISO 27001:2013 A.11.2.4", + "ISO 27001:2013 A.11.2.5", + "ISO 27001:2013 A.11.2.6", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": domainArn + "/elasticsearch-enforce-https-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": domainArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Elasticsearch.7] Elasticsearch Service domains should be updated to the latest service software version", + "Description": "Elasticsearch Service domain " + + esDomainName + + " is up to date. Service provided message follows: " + + updateInformation, + "Remediation": { + "Recommendation": { + "Text": "For update information refer to the Service Software Updates section of the Amazon Elasticsearch Service Developer Guide", + "Url": "https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-managedomains.html#es-service-software", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": domainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": domainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.MA-1", + "NIST SP 800-53 MA-2", + "NIST SP 800-53 MA-3", + "NIST SP 800-53 MA-5", + "NIST SP 800-53 MA-6", + "AICPA TSC CC8.1", + "ISO 27001:2013 A.11.1.2", + "ISO 27001:2013 A.11.2.4", + "ISO 27001:2013 A.11.2.5", + "ISO 27001:2013 A.11.2.6", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_Kinesis_Data_Streams_Auditor.py b/eeauditor/auditors/Amazon_Kinesis_Data_Streams_Auditor.py new file mode 100644 index 00000000..fe3fbff2 --- /dev/null +++ b/eeauditor/auditors/Amazon_Kinesis_Data_Streams_Auditor.py @@ -0,0 +1,296 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +kinesis = boto3.client("kinesis") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through kinesis streams +response = kinesis.list_streams(Limit=100) +myKinesisStreams = response["StreamNames"] + + +class KinesisStreamEncryptionCheck(Auditor): + def execute(self): + for streams in myKinesisStreams: + response = kinesis.describe_stream(StreamName=streams) + streamArn = str(response["StreamDescription"]["StreamARN"]) + streamName = str(response["StreamDescription"]["StreamName"]) + streamEncryptionCheck = str(response["StreamDescription"]["EncryptionType"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if streamEncryptionCheck == "NONE": + finding = { + "SchemaVersion": "2018-10-08", + "Id": streamArn + "/kinesis-streams-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": streamArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Kinesis.1] Kinesis Data Streams should be encrypted", + "Description": "Kinesis data stream " + + streamName + + " is not encrypted. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Data Stream encryption refer to the How Do I Get Started with Server-Side Encryption? section of the Amazon Kinesis Data Streams Developer Guide", + "Url": "https://docs.aws.amazon.com/streams/latest/dev/getting-started-with-sse.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisStream", + "Id": streamArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"StreamName": streamName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": streamArn + "/kinesis-streams-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": streamArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Kinesis.1] Kinesis Data Streams should be encrypted", + "Description": "Kinesis data stream " + + streamName + + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Data Stream encryption refer to the How Do I Get Started with Server-Side Encryption? section of the Amazon Kinesis Data Streams Developer Guide", + "Url": "https://docs.aws.amazon.com/streams/latest/dev/getting-started-with-sse.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisStream", + "Id": streamArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"StreamName": streamName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class KinesisEnhancedMonitoringCheck(Auditor): + def execute(self): + for streams in myKinesisStreams: + response = kinesis.describe_stream(StreamName=streams) + streamArn = str(response["StreamDescription"]["StreamARN"]) + streamName = str(response["StreamDescription"]["StreamName"]) + streamEnhancedMonitoring = response["StreamDescription"][ + "EnhancedMonitoring" + ] + for enhancedmonitors in streamEnhancedMonitoring: + shardLevelMetricCheck = str(enhancedmonitors["ShardLevelMetrics"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if shardLevelMetricCheck == "[]": + finding = { + "SchemaVersion": "2018-10-08", + "Id": streamArn + "/kinesis-streams-enhanced-monitoring-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": streamArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[Kinesis.2] Business-critical Kinesis Data Streams should have detailed monitoring configured", + "Description": "Kinesis data stream " + + streamName + + " does not have detailed monitoring configured, detailed monitoring allows shard-level metrics to be delivered every minute at additional cost. Business-critical streams should be considered for this configuration. Refer to the remediation instructions for information on this configuration", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Data Stream enhanced monitoring refer to the Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch section of the Amazon Kinesis Data Streams Developer Guide", + "Url": "https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisStream", + "Id": streamArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"StreamName": streamName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": streamArn + "/kinesis-streams-enhanced-monitoring-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": streamArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Kinesis.2] Business-critical Kinesis Data Streams should have detailed monitoring configured", + "Description": "Kinesis data stream " + + streamName + + " has detailed monitoring configured.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Data Stream enhanced monitoring refer to the Monitoring the Amazon Kinesis Data Streams Service with Amazon CloudWatch section of the Amazon Kinesis Data Streams Developer Guide", + "Url": "https://docs.aws.amazon.com/streams/latest/dev/monitoring-with-cloudwatch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisStream", + "Id": streamArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"StreamName": streamName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_Kinesis_Firehose_Auditor.py b/eeauditor/auditors/Amazon_Kinesis_Firehose_Auditor.py new file mode 100644 index 00000000..e8edf576 --- /dev/null +++ b/eeauditor/auditors/Amazon_Kinesis_Firehose_Auditor.py @@ -0,0 +1,176 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +firehose = boto3.client("firehose") +securityhub = boto3.client("securityhub") +# create region & account variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through Firehose delivery streams +try: + response = firehose.list_delivery_streams(Limit=100) + myFirehoseStreams = response["DeliveryStreamNames"] +except Exception as e: + print(e) + + +class FirehoseDeliveryStreamEncryptionCheck(Auditor): + def execute(self): + for deliverystreams in myFirehoseStreams: + firehoseName = str(deliverystreams) + try: + response = firehose.describe_delivery_stream( + DeliveryStreamName=firehoseName + ) + firehoseArn = str(response["DeliveryStreamARN"]) + firehoseEncryptionCheck = str( + response["DeliveryStreamDescription"][ + "DeliveryStreamEncryptionConfiguration" + ]["Status"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if firehoseEncryptionCheck == "DISABLED": + finding = { + "SchemaVersion": "2018-10-08", + "Id": firehoseArn + "/firehose-stream-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": firehoseArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Firehose.1] AWS Kinesis Firehose delivery streams should be encrypted", + "Description": "AWS Kinesis Firehose delivery stream " + + firehoseName + + " is not encrypted. If you send data to your delivery stream using PutRecord or PutRecordBatch, or if you send the data using AWS IoT, Amazon CloudWatch Logs, or CloudWatch Events, you can turn on server-side encryption by using the StartDeliveryStreamEncryption operation. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Firehose encryption refer to the Data Protection in Amazon Kinesis Data Firehose section of the Amazon Kinesis Data Firehose Developer Guide", + "Url": "https://docs.aws.amazon.com/firehose/latest/dev/encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisFirehoseDeliveryStream", + "Id": firehoseArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"deliveryStreamName": firehoseName} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + elif firehoseEncryptionCheck == "ENABLED": + finding = { + "SchemaVersion": "2018-10-08", + "Id": firehoseArn + "/firehose-stream-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": firehoseArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Firehose.1] AWS Kinesis Firehose delivery streams should be encrypted", + "Description": "AWS Kinesis Firehose delivery stream " + + firehoseName + + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Kinesis Firehose encryption refer to the Data Protection in Amazon Kinesis Data Firehose section of the Amazon Kinesis Data Firehose Developer Guide", + "Url": "https://docs.aws.amazon.com/firehose/latest/dev/encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsKinesisFirehoseDeliveryStream", + "Id": firehoseArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"deliveryStreamName": firehoseName} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_MQ_Auditor.py b/eeauditor/auditors/Amazon_MQ_Auditor.py new file mode 100644 index 00000000..4f5a029a --- /dev/null +++ b/eeauditor/auditors/Amazon_MQ_Auditor.py @@ -0,0 +1,773 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +securityhub = boto3.client("securityhub") +amzmq = boto3.client("mq") +sts = boto3.client("sts") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through Amazon MQ Brokers +try: + response = amzmq.list_brokers(MaxResults=100) + myBrokers = response["BrokerSummaries"] +except Exception as e: + print(e) + + +class BrokerKmsCmkCheck(Auditor): + def execute(self): + for broker in myBrokers: + brokerName = str(broker["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + kmsCmkCheck = str(response["EncryptionOptions"]["UseAwsOwnedKey"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if kmsCmkCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-kms-cmk-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AmazonMQ.1] AmazonMQ message brokers should use customer-managed KMS CMKs for encryption", + "Description": "AmazonMQ broker " + + brokerName + + " does not use a customer-managed KMS CMK for encryption. Customer managed CMKs are CMKs in your AWS account that you create, own, and manage. You have full control over these CMKs, including establishing and maintaining their key policies, IAM policies, and grants, enabling and disabling them, rotating their cryptographic material, adding tags, creating aliases that refer to the CMK, and scheduling the CMKs for deletion. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on encryption at rest considerations for Amazon MQ refer to the Encryption at Rest section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-encryption.html#encryption-at-rest", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + kmsKeyId = str(response["EncryptionOptions"]["KmsKeyId"]) + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-kms-cmk-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.1] AmazonMQ message brokers should use customer-managed KMS CMKs for encryption", + "Description": "AmazonMQ broker " + + brokerName + + " uses a customer-managed KMS CMK for encryption.", + "Remediation": { + "Recommendation": { + "Text": "For more information on encryption at rest considerations for Amazon MQ refer to the Encryption at Rest section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-encryption.html#encryption-at-rest", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + "kmsKeyId": kmsKeyId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class BrokerAuditLoggingCheck(Auditor): + def execute(self): + for broker in myBrokers: + brokerName = str(broker["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + auditLogCheck = str(response["Logs"]["Audit"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if auditLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AmazonMQ.2] AmazonMQ message brokers should have audit logging enabled", + "Description": "AmazonMQ broker " + + brokerName + + " does not have audit logging enabled. Audit logging enables logging of management actions taken using JMX or using the ActiveMQ Web Console and publishes audit.log to a log group in CloudWatch. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.2] AmazonMQ message brokers should have audit logging enabled", + "Description": "AmazonMQ broker " + + brokerName + + " has audit logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class BrokerGeneralLoggingCheck(Auditor): + def execute(self): + for broker in myBrokers: + brokerName = str(broker["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + genLogCheck = str(response["Logs"]["General"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if genLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-general-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AmazonMQ.3] AmazonMQ message brokers should have general logging enabled", + "Description": "AmazonMQ broker " + + brokerName + + " does not have general logging enabled. General logging enables the default INFO logging level (DEBUG logging isnt supported) and publishes activemq.log to a log group in CloudWatch. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-broker-general-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.3] AmazonMQ message brokers should have general logging enabled", + "Description": "AmazonMQ broker " + + brokerName + + " has general logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker logging refer to the Understanding the Structure of Logging in CloudWatch Logs section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-configuring-cloudwatch-logs.html#structure-of-logging-cloudwatch-logs", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class BrokerPublicAccessCheck(Auditor): + def execute(self): + for broker in myBrokers: + brokerName = str(broker["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + publicAccessCheck = str(response["PubliclyAccessible"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if publicAccessCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-public-accessible-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.4] AmazonMQ message brokers should not be publicly accessible", + "Description": "AmazonMQ broker " + + brokerName + + " is publicly accessible. Brokers created without public accessibility cannot be accessed from outside of your VPC. This greatly reduces your susceptibility to Distributed Denial of Service (DDoS) attacks from the public internet. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker accessibility through a VPC refer to the Accessing the ActiveMQ Web Console of a Broker without Public Accessibility section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/accessing-web-console-of-broker-without-private-accessibility.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-public-accessible-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.4] AmazonMQ message brokers should not be publicly accessible", + "Description": "AmazonMQ broker " + + brokerName + + " is not publicly accessible.", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker accessibility through a VPC refer to the Accessing the ActiveMQ Web Console of a Broker without Public Accessibility section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/accessing-web-console-of-broker-without-private-accessibility.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class BrokerMinorVersionAutoUpgradeCheck(Auditor): + def execute(self): + for broker in myBrokers: + brokerName = str(broker["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + autoUpgrMinorVersionCheck = str(response["AutoMinorVersionUpgrade"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if autoUpgrMinorVersionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-auto-minor-version-upgrade-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AmazonMQ.5] AmazonMQ message brokers should be configured to automatically upgrade to the latest minor version", + "Description": "AmazonMQ broker " + + brokerName + + " is not configured to automatically upgrade to the latest minor version. To upgrade the broker to new versions as AWS releases them, choose Enable automatic minor version upgrades. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker auto upgrades refer to the Tutorial: Editing Broker Engine Version, Instance Type, CloudWatch Logs, and Maintenance Preferences section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-editing-broker-preferences.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.MA-1", + "NIST SP 800-53 MA-2", + "NIST SP 800-53 MA-3", + "NIST SP 800-53 MA-5", + "NIST SP 800-53 MA-6", + "AICPA TSC CC8.1", + "ISO 27001:2013 A.11.1.2", + "ISO 27001:2013 A.11.2.4", + "ISO 27001:2013 A.11.2.5", + "ISO 27001:2013 A.11.2.6", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + "/amazonmq-auto-minor-version-upgrade-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AmazonMQ.5] AmazonMQ message brokers should be configured to automatically upgrade to the latest minor version", + "Description": "AmazonMQ broker " + + brokerName + + " is configured to automatically upgrade to the latest minor version.", + "Remediation": { + "Recommendation": { + "Text": "For more information on message broker auto upgrades refer to the Tutorial: Editing Broker Engine Version, Instance Type, CloudWatch Logs, and Maintenance Preferences section of the Amazon MQ Developer Guide", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/amazon-mq-editing-broker-preferences.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.MA-1", + "NIST SP 800-53 MA-2", + "NIST SP 800-53 MA-3", + "NIST SP 800-53 MA-5", + "NIST SP 800-53 MA-6", + "AICPA TSC CC8.1", + "ISO 27001:2013 A.11.1.2", + "ISO 27001:2013 A.11.2.4", + "ISO 27001:2013 A.11.2.5", + "ISO 27001:2013 A.11.2.6", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_MSK_Auditor.py b/eeauditor/auditors/Amazon_MSK_Auditor.py new file mode 100644 index 00000000..aff7f208 --- /dev/null +++ b/eeauditor/auditors/Amazon_MSK_Auditor.py @@ -0,0 +1,577 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +kafka = boto3.client("kafka") +securityhub = boto3.client("securityhub") +# create env vars for account and region +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through managed kafka clusters +response = kafka.list_clusters() +myMskClusters = response["ClusterInfoList"] + + +class InterClusterEncryptionInTransitCheck(Auditor): + def execute(self): + for clusters in myMskClusters: + clusterArn = str(clusters["ClusterArn"]) + clusterName = str(clusters["ClusterName"]) + interClusterEITCheck = str( + clusters["EncryptionInfo"]["EncryptionInTransit"]["InCluster"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if interClusterEITCheck != "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/intercluster-encryption-in-transit", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[MSK.1] Managed Kafka Stream clusters should have inter-cluster encryption in transit enabled", + "Description": "MSK cluster " + + clusterName + + " does not have inter-cluster encryption in transit enabled. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have inter-cluster encryption in transit enabled refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/intercluster-encryption-in-transit", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[MSK.1] Managed Kafka Stream clusters should have inter-cluster encryption in transit enabled", + "Description": "MSK cluster " + + clusterName + + " has inter-cluster encryption in transit enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should have inter-cluster encryption in transit enabled refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class ClientBrokerEncryptionInTransitCheck(Auditor): + def execute(self): + for clusters in myMskClusters: + clusterArn = str(clusters["ClusterArn"]) + clusterName = str(clusters["ClusterName"]) + clientBrokerTlsCheck = str( + clusters["EncryptionInfo"]["EncryptionInTransit"]["ClientBroker"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if clientBrokerTlsCheck != "TLS": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/client-broker-tls", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[MSK.2] Managed Kafka Stream clusters should enforce TLS-only communications between clients and brokers", + "Description": "MSK cluster " + + clusterName + + " does not enforce TLS-only communications between clients and brokers. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should enforce TLS-only communications between clients and brokers refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/client-broker-tls", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[MSK.2] Managed Kafka Stream clusters should enforce TLS-only communications between clients and brokers", + "Description": "MSK cluster " + + clusterName + + " enforces TLS-only communications between clients and brokers", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should enforce TLS-only communications between clients and brokers refer to the How Do I Get Started with Encryption? section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-working-with-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class ClientAuthenticationCheck(Auditor): + def execute(self): + for clusters in myMskClusters: + clusterArn = str(clusters["ClusterArn"]) + clusterName = str(clusters["ClusterName"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + clientAuthCheck = str( + clusters["ClientAuthentication"]["Tls"][ + "CertificateAuthorityArnList" + ] + ) + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/tls-client-auth", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[MSK.3] Managed Kafka Stream clusters should use TLS for client authentication", + "Description": "MSK cluster " + + clusterName + + " uses TLS for client authentication.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should use TLS for client authentication refer to the Client Authentication section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/tls-client-auth", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[MSK.3] Managed Kafka Stream clusters should use TLS for client authentication", + "Description": "MSK cluster " + + clusterName + + " does not use TLS for client authentication. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should use TLS for client authentication refer to the Client Authentication section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/msk-authentication.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class ClusterEnhancedMonitoringCheck(Auditor): + def execute(self): + for clusters in myMskClusters: + clusterArn = str(clusters["ClusterArn"]) + clusterName = str(clusters["ClusterName"]) + enhancedMonitoringCheck = str(clusters["EnhancedMonitoring"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if enhancedMonitoringCheck == "DEFAULT": + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/detailed-monitoring", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[MSK.4] Managed Kafka Stream clusters should use enhanced monitoring", + "Description": "MSK cluster " + + clusterName + + " does not use enhanced monitoring. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should use enhanced monitoring refer to the Monitoring an Amazon MSK Cluster section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/monitoring.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clusterArn + "/detailed-monitoring", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clusterArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[MSK.4] Managed Kafka Stream clusters should use enhanced monitoring", + "Description": "MSK cluster " + + clusterName + + " uses enhanced monitoring.", + "Remediation": { + "Recommendation": { + "Text": "If your cluster should use enhanced monitoring refer to the Monitoring an Amazon MSK Cluster section of the Amazon Managed Streaming for Apache Kakfa Developer Guide", + "Url": "https://docs.aws.amazon.com/msk/latest/developerguide/monitoring.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedKafkaCluster", + "Id": clusterArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"ClusterName": clusterName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + diff --git a/eeauditor/auditors/Amazon_Managed_Blockchain_Auditor.py b/eeauditor/auditors/Amazon_Managed_Blockchain_Auditor.py new file mode 100644 index 00000000..35820f42 --- /dev/null +++ b/eeauditor/auditors/Amazon_Managed_Blockchain_Auditor.py @@ -0,0 +1,564 @@ +import boto3 +import datetime +import os +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +amb = boto3.client("managedblockchain") +securityhub = boto3.client("securityhub") +# create account id & region variables +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +# loop through AMB Fabric networks +try: + response = amb.list_networks(Framework="HYPERLEDGER_FABRIC") + myFabricNetworks = response["Networks"] +except Exception as e: + print(e) + + +class AmbFabricNodeChaincodeLoggingCheck(Auditor): + def execute(self): + for networks in myFabricNetworks: + fabricNetworkId = str(networks["Id"]) + try: + response = amb.list_members( + NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True + ) + for members in response["Members"]: + memberId = str(members["Id"]) + try: + response = amb.list_nodes( + NetworkId=fabricNetworkId, + MemberId=memberId, + Status="AVAILABLE", + ) + for nodes in response["Nodes"]: + peerNodeId = str(nodes["Id"]) + try: + response = amb.get_node( + NetworkId=fabricNetworkId, + MemberId=memberId, + NodeId=peerNodeId, + ) + nodeArn = ( + "arn:aws:managedblockchain:" + + awsRegion + + ":" + + awsAccountId + + ":nodes/" + + peerNodeId + ) + chaincodeLogCheck = str( + response["Node"]["LogPublishingConfiguration"][ + "Fabric" + ]["ChaincodeLogs"]["Cloudwatch"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if chaincodeLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": nodeArn + + "/managedblockchain-fabric-node-chaincode-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": nodeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AMB.Fabric.1] Amazon Managed Blockchain Fabric peer nodes should have chaincode logging enabled", + "Description": "Amazon Managed Blockchain Fabric peer node " + + peerNodeId + + " does not have chaincode logging enabled. Chaincode logs help you analyze and debug the business logic and execution of chaincode on a peer node. They contain the results of instantiating, invoking, and querying the chaincode. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsManagedBlockchainPeerNode", + "Id": nodeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + "nodeId": peerNodeId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": nodeArn + + "/managedblockchain-fabric-node-chaincode-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": nodeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AMB.Fabric.1] Amazon Managed Blockchain Fabric peer nodes should have chaincode logging enabled", + "Description": "Amazon Managed Blockchain Fabric peer node " + + peerNodeId + + " has chaincode logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsManagedBlockchainPeerNode", + "Id": nodeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + "nodeId": peerNodeId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + except Exception as e: + print(e) + + +class AmbFabricNodePeernodeLoggingCheck(Auditor): + def execute(self): + for networks in myFabricNetworks: + fabricNetworkId = str(networks["Id"]) + try: + response = amb.list_members( + NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True + ) + for members in response["Members"]: + memberId = str(members["Id"]) + try: + response = amb.list_nodes( + NetworkId=fabricNetworkId, + MemberId=memberId, + Status="AVAILABLE", + ) + for nodes in response["Nodes"]: + peerNodeId = str(nodes["Id"]) + try: + response = amb.get_node( + NetworkId=fabricNetworkId, + MemberId=memberId, + NodeId=peerNodeId, + ) + nodeArn = ( + "arn:aws:managedblockchain:" + + awsRegion + + ":" + + awsAccountId + + ":nodes/" + + peerNodeId + ) + peerNodeLogCheck = str( + response["Node"]["LogPublishingConfiguration"][ + "Fabric" + ]["PeerLogs"]["Cloudwatch"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if peerNodeLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": nodeArn + + "/managedblockchain-fabric-node-peernode-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": nodeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AMB.Fabric.2] Amazon Managed Blockchain Fabric peer nodes should have peer node logging enabled", + "Description": "Amazon Managed Blockchain Fabric peer node " + + peerNodeId + + " does not have peer node logging enabled. Peer node logs help you debug timeout errors associated with proposals and identify rejected proposals that do not meet the endorsement policies. Peer node logs contain messages generated when your client submits transaction proposals to peer nodes, requests to join channels, enrolls an admin peer, and lists the chaincode instances on a peer node. Peer node logs also contain the results of chaincode installation. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsManagedBlockchainPeerNode", + "Id": nodeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + "nodeId": peerNodeId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": nodeArn + + "/managedblockchain-fabric-node-peernode-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": nodeArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AMB.Fabric.2] Amazon Managed Blockchain Fabric peer nodes should have peer node logging enabled", + "Description": "Amazon Managed Blockchain Fabric peer node " + + peerNodeId + + " has peer node logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsManagedBlockchainPeerNode", + "Id": nodeArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + "nodeId": peerNodeId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) + except Exception as e: + print(e) + + +class AmbFabricMemberCaLoggingCheck(Auditor): + def execute(self): + for networks in myFabricNetworks: + fabricNetworkId = str(networks["Id"]) + try: + response = amb.list_members( + NetworkId=fabricNetworkId, Status="AVAILABLE", IsOwned=True + ) + for members in response["Members"]: + memberId = str(members["Id"]) + try: + response = amb.get_member( + NetworkId=fabricNetworkId, MemberId=memberId + ) + memberArn = ( + "arn:aws:managedblockchain:" + + awsRegion + + ":" + + awsAccountId + + ":members/" + + memberId + ) + memberCaLogCheck = str( + response["Member"]["LogPublishingConfiguration"]["Fabric"][ + "CaLogs" + ]["Cloudwatch"]["Enabled"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if memberCaLogCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": memberArn + + "/managedblockchain-member-ca-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": memberArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[AMB.Fabric.3] Amazon Managed Blockchain Fabric members should have certificate authority (CA) logging enabled", + "Description": "Amazon Managed Blockchain Fabric member " + + memberId + + " does not have certificate authority (CA) logging enabled. CA logs help you determine when a member in your account joins the network, or when new peers register with a member CA. You can use CA logs to debug problems related to certificates and enrollment. CA logging can be enabled and disabled for each member. A single log stream for the CA exists for each member. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedBlockchainMember", + "Id": memberArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": memberArn + + "/managedblockchain-member-ca-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": memberArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[AMB.Fabric.3] Amazon Managed Blockchain Fabric members should have certificate authority (CA) logging enabled", + "Description": "Amazon Managed Blockchain Fabric member " + + memberId + + " has certificate authority (CA) logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on logging and monitoring Amazon Managed Blockchain refer to the Enabling and Disabling Logs section of the Amazon Managed Blockchain Management Guide", + "Url": "https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/monitoring-cloudwatch-logs.html#monitoring-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsManagedBlockchainMember", + "Id": memberArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "networkId": fabricNetworkId, + "memberId": memberId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print(e) diff --git a/eeauditor/auditors/Amazon_Neptune_Auditor.py b/eeauditor/auditors/Amazon_Neptune_Auditor.py new file mode 100644 index 00000000..127fa9e9 --- /dev/null +++ b/eeauditor/auditors/Amazon_Neptune_Auditor.py @@ -0,0 +1,750 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +neptune = boto3.client("neptune") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through neptune instances +neptune_instances = neptune.describe_db_instances( + Filters=[{"Name": "engine", "Values": ["neptune"]}] +) + + +class NeptuneInstanceMultiAzCheck(Auditor): + def execute(self): + for instances in neptune_instances["DBInstances"]: + neptuneInstanceArn = str(instances["DBInstanceArn"]) + neptuneDbId = str(instances["DBInstanceIdentifier"]) + mutliAzCheck = str(instances["MultiAZ"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if mutliAzCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + "/neptune-instance-ha-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[Neptune.1] Neptune database instances should be configured to be highly available", + "Description": "Neptune database instance " + + neptuneDbId + + " does not have Multi-AZ enabled and thus is not highly available. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune High Availability and how to configure it refer to the High Availability for Neptune section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/feature-overview-availability.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + "/neptune-instance-ha-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Neptune.1] Neptune database instances should be configured to be highly available", + "Description": "Neptune database instance " + + neptuneDbId + + " is highly available.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune High Availability and how to configure it refer to the High Availability for Neptune section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/feature-overview-availability.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class NeptuneInstanceStorageEncryptionCheck(Auditor): + def execute(self): + for instances in neptune_instances["DBInstances"]: + neptuneInstanceArn = str(instances["DBInstanceArn"]) + neptuneDbId = str(instances["DBInstanceIdentifier"]) + storageEncryptionCheck = str(instances["StorageEncrypted"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if storageEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + + "/neptune-instance-storage-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[Neptune.2] Neptune database instace storage should be encrypted", + "Description": "Neptune database instance " + + neptuneDbId + + " does not have storage encryption enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune storage encryption and how to configure it refer to the Enabling Encryption for a Neptune DB Instance section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/encrypt.html#encrypt-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + + "/neptune-instance-storage-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Neptune.2] Neptune database instace storage should be encrypted", + "Description": "Neptune database instance " + + neptuneDbId + + " has storage encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune storage encryption and how to configure it refer to the Enabling Encryption for a Neptune DB Instance section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/encrypt.html#encrypt-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class NeptuneInstanceIamAuthenticationCheck(Auditor): + def execute(self): + for instances in neptune_instances["DBInstances"]: + neptuneInstanceArn = str(instances["DBInstanceArn"]) + neptuneDbId = str(instances["DBInstanceIdentifier"]) + iamDbAuthCheck = str(instances["IAMDatabaseAuthenticationEnabled"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if iamDbAuthCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + "/neptune-instance-iam-db-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Neptune.3] Neptune database instaces storage should use IAM Database Authentication", + "Description": "Neptune database instance " + + neptuneDbId + + " does not use IAM Database Authentication. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune IAM Database Authentication and how to configure it refer to the Neptune Database Authentication Using IAM section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": neptuneInstanceArn + "/neptune-instance-iam-db-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": neptuneInstanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Neptune.3] Neptune database instaces storage should use IAM Database Authentication", + "Description": "Neptune database instance " + + neptuneDbId + + " uses IAM Database Authentication.", + "Remediation": { + "Recommendation": { + "Text": "For more information on Neptune IAM Database Authentication and how to configure it refer to the Neptune Database Authentication Using IAM section of the Amazon Neptune User Guide", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/iam-auth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": neptuneInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"InstanceId": neptuneDbId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class NeptuneClusterParameterSslEnforcementCheck(Auditor): + def execute(self): + response = neptune.describe_db_cluster_parameter_groups() + for parametergroup in response["DBClusterParameterGroups"]: + parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) + parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) + response = neptune.describe_db_cluster_parameters( + DBClusterParameterGroupName=parameterGroupName + ) + for parameters in response["Parameters"]: + if str(parameters["ParameterName"]) == "neptune_enforce_ssl": + sslEnforcementCheck = str(parameters["ParameterValue"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if sslEnforcementCheck == "0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/neptune-cluster-param-group-ssl-enforcement-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Neptune.4] Neptune cluster parameter groups should enforce SSL connections to Neptune databases", + "Description": "Neptune cluster parameter group " + + parameterGroupName + + " does not enforce SSL connections. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on enforcing SSL/HTTPS connections to Neptune instances refer to the Encryption in Transit: Connecting to Neptune Using SSL/HTTPS section of the Amazon Neptune User Guide.", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/security-ssl.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/neptune-cluster-param-group-ssl-enforcement-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Neptune.4] Neptune cluster parameter groups should enforce SSL connections to Neptune databases", + "Description": "Neptune cluster parameter group " + + parameterGroupName + + " enforces SSL connections.", + "Remediation": { + "Recommendation": { + "Text": "For more information on enforcing SSL/HTTPS connections to Neptune instances refer to the Encryption in Transit: Connecting to Neptune Using SSL/HTTPS section of the Amazon Neptune User Guide.", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/security-ssl.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-2", + "NIST SP 800-53 SC-8", + "NIST SP 800-53 SC-11", + "NIST SP 800-53 SC-12", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.13.2.3", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class NeptuneClusterParameterAuditLogCheck(Auditor): + def execute(self): + response = neptune.describe_db_cluster_parameter_groups() + for parametergroup in response["DBClusterParameterGroups"]: + parameterGroupName = str(parametergroup["DBClusterParameterGroupName"]) + parameterGroupArn = str(parametergroup["DBClusterParameterGroupArn"]) + response = neptune.describe_db_cluster_parameters( + DBClusterParameterGroupName=parameterGroupName + ) + for parameters in response["Parameters"]: + if str(parameters["ParameterName"]) == "neptune_enable_audit_log": + auditLogCheck = str(parameters["ParameterValue"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if auditLogCheck == "0": + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/neptune-cluster-param-group-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[Neptune.5] Neptune cluster parameter groups should enforce audit logging for Neptune databases", + "Description": "Neptune cluster parameter group " + + parameterGroupName + + " does not enforce audit logging. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on audit logging for Neptune instances refer to the Enabling Neptune Audit Logs section of the Amazon Neptune User Guide.", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/auditing.html#auditing-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": parameterGroupArn + + "/neptune-cluster-param-group-audit-logging-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": parameterGroupArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Neptune.5] Neptune cluster parameter groups should enforce audit logging for Neptune databases", + "Description": "Neptune cluster parameter group " + + parameterGroupName + + " enforces audit logging.", + "Remediation": { + "Recommendation": { + "Text": "For more information on audit logging for Neptune instances refer to the Enabling Neptune Audit Logs section of the Amazon Neptune User Guide.", + "Url": "https://docs.aws.amazon.com/neptune/latest/userguide/auditing.html#auditing-enable", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": parameterGroupArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ParameterGroupName": parameterGroupName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass diff --git a/eeauditor/auditors/Amazon_RDS_Auditor.py b/eeauditor/auditors/Amazon_RDS_Auditor.py new file mode 100644 index 00000000..c4a76f6e --- /dev/null +++ b/eeauditor/auditors/Amazon_RDS_Auditor.py @@ -0,0 +1,1619 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +rds = boto3.client("rds") +securityhub = boto3.client("securityhub") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through all RDS DB instances +response = rds.describe_db_instances( + Filters=[ + { + "Name": "engine", + "Values": [ + "aurora", + "aurora-mysql", + "aurora-postgresql", + "mariadb", + "mysql", + "oracle-ee", + "postgres", + "sqlserver-ee", + "sqlserver-se", + "sqlserver-ex", + "sqlserver-web", + ], + } + ], + MaxRecords=100, +) +myRdsInstances = response["DBInstances"] +# loop through all RDS DB snapshots +response = rds.describe_db_snapshots() +myRdsSnapshots = response["DBSnapshots"] + + +class RdsInstanceHaCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + highAvailabilityCheck = str(dbinstances["MultiAZ"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if highAvailabilityCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-ha-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[RDS.1] RDS instances should be configured for high availability", + "Description": "RDS DB instance " + + instanceId + + " is not configured for high availability. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instance high availability and how to configure it refer to the High Availability (Multi-AZ) for Amazon RDS section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-ha-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[RDS.1] RDS instances should be configured for high availability", + "Description": "RDS DB instance " + + instanceId + + " is configured for high availability.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instance high availability and how to configure it refer to the High Availability (Multi-AZ) for Amazon RDS section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsInstancePublicAccessCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + publicAccessibleCheck = str(dbinstances["PubliclyAccessible"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if publicAccessibleCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-public-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[RDS.2] RDS instances should not be publicly accessible", + "Description": "RDS DB instance " + + instanceId + + " is publicly accessible. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instance publicly access and how to change it refer to the Hiding a DB Instance in a VPC from the Internet section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "PubliclyAccessible": True, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-public-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.2] RDS instances should not be publicly accessible", + "Description": "RDS DB instance " + + instanceId + + " is not publicly accessible. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instance publicly access and how to change it refer to the Hiding a DB Instance in a VPC from the Internet section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_VPC.WorkingWithRDSInstanceinaVPC.html#USER_VPC.Hiding", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "PubliclyAccessible": False, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsInstanceStorageEncryptionCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + rdsStorageEncryptionCheck = str(dbinstances["StorageEncrypted"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if rdsStorageEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-storage-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[RDS.3] RDS instances should have encrypted storage", + "Description": "RDS DB instance " + + instanceId + + " does not have encrypted storage. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS storage encryption refer to the Enabling Amazon RDS Encryption for a DB Instance section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html#Overview.Encryption.Enabling", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "StorageEncrypted": False, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-storage-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.3] RDS instances should have encrypted storage", + "Description": "RDS DB instance " + + instanceId + + " has encrypted storage.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS storage encryption refer to the Enabling Amazon RDS Encryption for a DB Instance section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html#Overview.Encryption.Enabling", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "StorageEncrypted": True, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsInstanceIamAuthCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + iamDbAuthCheck = str(dbinstances["IAMDatabaseAuthenticationEnabled"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if instanceEngine == "mysql" or "postgres": + if iamDbAuthCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-iam-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[RDS.4] RDS instances that support IAM Authentication should use IAM Authentication", + "Description": "RDS DB instance " + + instanceId + + " does not support IAM Authentication. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS IAM Database Authentication and how to configure it refer to the IAM Database Authentication for MySQL and PostgreSQL section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "IAMDatabaseAuthenticationEnabled": False, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-iam-auth-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.4] RDS instances that support IAM Authentication should use IAM Authentication", + "Description": "RDS DB instance " + + instanceId + + " supports IAM Authentication.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS IAM Database Authentication and how to configure it refer to the IAM Database Authentication for MySQL and PostgreSQL section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + "IAMDatabaseAuthenticationEnabled": True, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class RdsInstanceDomainJoinCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + activeDirectoryDomainCheck = str(dbinstances["DomainMemberships"]) + if ( + instanceEngine == "mysql" + or "oracle-ee" + or "oracle-se1" + or "oracle-se2" + or "oracle-se" + or "postgres" + or "sqlserver-ee" + or "sqlserver-se" + or "sqlserver-ex" + or "sqlserver-web" + ): + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if activeDirectoryDomainCheck == "[]": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-domain-join-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[RDS.5] RDS instances that support Kerberos Authentication should be joined to a domain", + "Description": "RDS DB instance " + + instanceId + + " is not joined to a domain, and likely does not support Kerberos Authentication because of it. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instances that support Kerberos Authentication and how to configure it refer to the Kerberos Authentication section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/kerberos-authentication.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-domain-join-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.5] RDS instances that support Kerberos Authentication should be joined to a domain", + "Description": "RDS DB instance " + + instanceId + + " is joined to a domain, and likely supports Kerberos Authentication because of it.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS instances that support Kerberos Authentication and how to configure it refer to the Kerberos Authentication section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/kerberos-authentication.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + pass + + +class RdsInstancePerformanceInsightsCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + perfInsightsCheck = str(dbinstances["PerformanceInsightsEnabled"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if perfInsightsCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-perf-insights-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[RDS.6] RDS instances should have performance insights enabled", + "Description": "RDS DB instance " + + instanceId + + " does not have performance insights enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS performance insights and how to configure it refer to the Using Amazon RDS Performance Insights section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-perf-insights-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.6] RDS instances should have performance insights enabled", + "Description": "RDS DB instance " + + instanceId + + " has performance insights enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS performance insights and how to configure it refer to the Using Amazon RDS Performance Insights section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_PerfInsights.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsInstanceDeletionProtectionCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + deletionProtectionCheck = str(dbinstances["DeletionProtection"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if deletionProtectionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-deletion-prot-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[RDS.7] RDS instances should have deletion protection enabled", + "Description": "RDS DB instance " + + instanceId + + " does not have deletion protection enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS deletion protection and how to configure it refer to the Deletion Protection section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_DeleteInstance.html#USER_DeleteInstance.DeletionProtection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "DeletionProtection": False, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-database-cloudwatch-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.7] RDS instances should have deletion protection enabled", + "Description": "RDS DB instance " + + instanceId + + " has deletion protection enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on RDS deletion protection and how to configure it refer to the Deletion Protection section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_DeleteInstance.html#USER_DeleteInstance.DeletionProtection", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "DeletionProtection": False, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsInstanceCloudwatchLoggingCheck(Auditor): + def execute(self): + for dbinstances in myRdsInstances: + instanceArn = str(dbinstances["DBInstanceArn"]) + instanceId = str(dbinstances["DBInstanceIdentifier"]) + instanceClass = str(dbinstances["DBInstanceClass"]) + instancePort = int(dbinstances["Endpoint"]["Port"]) + instanceEngine = str(dbinstances["Engine"]) + instanceEngineVersion = str(dbinstances["EngineVersion"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + logCheck = str(database["EnabledCloudwatchLogsExports"]) + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-database-cloudwatch-logs-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.8] RDS instances should publish database logs to CloudWatch Logs", + "Description": "RDS DB instance " + + instanceId + + " publishes " + + logCheck + + " logs to CloudWatch Logs. Review the types of logs that are published to ensure they fulfill organizational and regulatory requirements as needed.", + "Remediation": { + "Recommendation": { + "Text": "For more information on database logging with CloudWatch and how to configure it refer to the Publishing Database Logs to Amazon CloudWatch Logs section of the Amazon Relational Database Service User Guide. Aurora does support this but you will need to address another User Guide for information on Aurora database logging with CloudWatch", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": instanceArn + "/instance-deletion-prot-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": instanceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[RDS.8] RDS instances should publish database logs to CloudWatch Logs", + "Description": "RDS DB instance " + + instanceId + + " does not publish database logs to CloudWatch Logs. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on database logging with CloudWatch and how to configure it refer to the Publishing Database Logs to Amazon CloudWatch Logs section of the Amazon Relational Database Service User Guide. Aurora does support this but you will need to address another User Guide for information on Aurora database logging with CloudWatch", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.html#USER_LogAccess.Procedural.UploadtoCloudWatch", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": instanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": instanceId, + "DBInstanceClass": instanceClass, + "DbInstancePort": instancePort, + "Engine": instanceEngine, + "EngineVersion": instanceEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +class RdsSnapshotEncryptionCheck(Auditor): + def execute(self): + for snapshot in myRdsSnapshots: + snapshotId = str(snapshot["DBSnapshotIdentifier"]) + snapshotArn = str(snapshot["DBSnapshotArn"]) + snapshotEncryptionCheck = str(snapshot["Encrypted"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if snapshotEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/rds-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[RDS.9] RDS snapshots should be encrypted", + "Description": "RDS snapshot " + + snapshotId + + " is not encrypted. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on encrypting RDS snapshots refer to the AWS Premium Support Knowledge Center Entry How do I encrypt Amazon RDS snapshots?", + "Url": "https://aws.amazon.com/premiumsupport/knowledge-center/encrypt-rds-snapshots/", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbSnapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"SnapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/rds-snapshot-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.9] RDS snapshots should be encrypted", + "Description": "RDS snapshot " + snapshotId + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "For more information on encrypting RDS snapshots refer to the AWS Premium Support Knowledge Center Entry How do I encrypt Amazon RDS snapshots?", + "Url": "https://aws.amazon.com/premiumsupport/knowledge-center/encrypt-rds-snapshots/", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbSnapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"SnapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class RdsSnapshotPublicShareCheck(Auditor): + def execute(self): + for snapshot in myRdsSnapshots: + snapshotId = str(snapshot["DBSnapshotIdentifier"]) + snapshotArn = str(snapshot["DBSnapshotArn"]) + response = rds.describe_db_snapshot_attributes( + DBSnapshotIdentifier=snapshotId + ) + rdsSnapshotAttrs = response["DBSnapshotAttributesResult"][ + "DBSnapshotAttributes" + ] + for attribute in rdsSnapshotAttrs: + attrName = str(attribute["AttributeName"]) + if attrName == "restore": + attrValue = str(attribute["AttributeValues"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if attrValue == "['all']": + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/rds-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + "Sensitive Data Identifications", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "CRITICAL"}, + "Confidence": 99, + "Title": "[RDS.10] RDS snapshots should not be publicly shared", + "Description": "RDS snapshot " + + snapshotId + + " is publicly shared. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on sharing RDS snapshots refer to the Sharing a Snapshot section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ShareSnapshot.html#USER_ShareSnapshot.Sharing", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbSnapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"SnapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": snapshotArn + "/rds-snapshot-public-share-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": snapshotArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + "Sensitive Data Identifications", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[RDS.10] RDS snapshots should not be publicly shared", + "Description": "RDS snapshot " + + snapshotId + + " is not publicly shared.", + "Remediation": { + "Recommendation": { + "Text": "For more information on sharing RDS snapshots refer to the Sharing a Snapshot section of the Amazon Relational Database Service User Guide", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ShareSnapshot.html#USER_ShareSnapshot.Sharing", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbSnapshot", + "Id": snapshotArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"SnapshotId": snapshotId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + print("non-supported attribute encountered") + pass diff --git a/eeauditor/auditors/Amazon_Redshift_Auditor.py b/eeauditor/auditors/Amazon_Redshift_Auditor.py new file mode 100644 index 00000000..7affd281 --- /dev/null +++ b/eeauditor/auditors/Amazon_Redshift_Auditor.py @@ -0,0 +1,513 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +redshift = boto3.client('redshift') +# create env vars +awsRegion = os.environ['AWS_REGION'] +awsAccountId = sts.get_caller_identity()['Account'] +# loop through redshift clusters +response = redshift.describe_clusters() +myRedshiftClusters = response['Clusters'] + +class ClusterPublicAccessCheck(Auditor): + def execute(self): + for cluster in myRedshiftClusters: + clusterId = str(cluster['ClusterIdentifier']) + clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(cluster['PubliclyAccessible']) == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'CRITICAL' }, + 'Confidence': 99, + 'Title': '[Redshift.1] Redshift clusters should not be publicly accessible', + 'Description': 'Redshift cluster ' + clusterId + ' is publicly accessible. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on modifying Redshift public access refer to the Modifying a Cluster section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html#modify-cluster' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Redshift.1] Redshift clusters should not be publicly accessible', + 'Description': 'Redshift cluster ' + clusterId + ' is not publicly accessible.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on modifying Redshift public access refer to the Modifying a Cluster section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/managing-clusters-console.html#modify-cluster' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class ClusterEncryptionCheck(Auditor): + def execute(self): + for cluster in myRedshiftClusters: + clusterId = str(cluster['ClusterIdentifier']) + clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(cluster['Encrypted']) == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-cluster-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[Redshift.2] Redshift clusters should be encrypted', + 'Description': 'Redshift cluster ' + clusterId + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift cluster encryption and how to configure it refer to the Amazon Redshift Database Encryption section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-db-encryption.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-cluster-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Redshift.2] Redshift clusters should be encrypted', + 'Description': 'Redshift cluster ' + clusterId + ' is encrypted.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift cluster encryption and how to configure it refer to the Amazon Redshift Database Encryption section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-db-encryption.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class ClusterEnhancedVPCRoutingCheck(Auditor): + def execute(self): + for cluster in myRedshiftClusters: + clusterId = str(cluster['ClusterIdentifier']) + clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(cluster['EnhancedVpcRouting']) == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-cluster-enhanced-vpc-routing-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Redshift.3] Redshift clusters should utilize enhanced VPC routing', + 'Description': 'Redshift cluster ' + clusterId + ' is not utilizing enhanced VPC routing. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift Enhanced VPC routing and how to configure it refer to the Amazon Redshift Enhanced VPC Routing section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/enhanced-vpc-routing.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-enhanced-vpc-routing-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Redshift.3] Redshift clusters should utilize enhanced VPC routing', + 'Description': 'Redshift cluster ' + clusterId + ' is utilizing enhanced VPC routing.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift Enhanced VPC routing and how to configure it refer to the Amazon Redshift Enhanced VPC Routing section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/enhanced-vpc-routing.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class ClusterLoggingCheck(Auditor): + def execute(self): + for cluster in myRedshiftClusters: + clusterId = str(cluster['ClusterIdentifier']) + clusterArn = 'arn:aws:redshift:' + awsRegion + ':' + awsAccountId + ':cluster:' + clusterId + response = redshift.describe_logging_status(ClusterIdentifier=clusterId) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(response['LoggingEnabled']) == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-cluster-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[Redshift.4] Redshift clusters should have logging enabled', + 'Description': 'Redshift cluster ' + clusterId + ' does not have logging enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift logging and how to configure it refer to the Database Audit Logging section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': clusterArn + '/redshift-cluster-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': clusterArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[Redshift.4] Redshift clusters should have logging enabled', + 'Description': 'Redshift cluster ' + clusterId + ' has logging enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Redshift logging and how to configure it refer to the Database Audit Logging section of the Amazon Redshift Cluster Management Guide', + 'Url': 'https://docs.aws.amazon.com/redshift/latest/mgmt/db-auditing.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsRedshiftCluster', + 'Id': clusterArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'ClusterId': clusterId + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/Amazon_S3_Auditor.py b/eeauditor/auditors/Amazon_S3_Auditor.py new file mode 100644 index 00000000..43e8b9b3 --- /dev/null +++ b/eeauditor/auditors/Amazon_S3_Auditor.py @@ -0,0 +1,865 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +s3 = boto3.client('s3') +s3control = boto3.client('s3control') +# create env vars +awsRegion = os.environ['AWS_REGION'] +awsAccountId = sts.get_caller_identity()['Account'] +# loop through s3 buckets +response = s3.list_buckets() +myS3Buckets = response['Buckets'] + +class BucketEncryptionCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + try: + response = s3.get_bucket_encryption(Bucket=bucketName) + for rules in response['ServerSideEncryptionConfiguration']['Rules']: + sseType = str(rules['ApplyServerSideEncryptionByDefault']['SSEAlgorithm']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.1] S3 Buckets should be encrypted', + 'Description': 'S3 bucket ' + bucketName + ' is encrypted using ' + sseType + '.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Encryption and how to configure it refer to the Amazon S3 Default Encryption for S3 Buckets section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == 'An error occurred (ServerSideEncryptionConfigurationNotFoundError) when calling the GetBucketEncryption operation: The server side encryption configuration was not found': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[S3.1] S3 Buckets should be encrypted', + 'Description': 'S3 bucket ' + bucketName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Encryption and how to configure it refer to the Amazon S3 Default Encryption for S3 Buckets section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/bucket-encryption.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class BucketLifecycleCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = s3.get_bucket_lifecycle_configuration(Bucket=bucketName) + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-lifecyle-configuration-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.2] S3 Buckets should implement lifecycle policies for data archival and recovery operations', + 'Description': 'S3 bucket ' + bucketName + ' has a lifecycle policy configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Lifecycle policies and how to configure it refer to the How Do I Create a Lifecycle Policy for an S3 Bucket? section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == 'An error occurred (NoSuchLifecycleConfiguration) when calling the GetBucketLifecycleConfiguration operation: The lifecycle configuration does not exist': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-lifecyle-configuration-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[S3.2] S3 Buckets should implement lifecycle policies for data archival and recovery operations', + 'Description': 'S3 bucket ' + bucketName + ' does not have a lifecycle policy configured. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Lifecycle policies and how to configure it refer to the How Do I Create a Lifecycle Policy for an S3 Bucket? section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class BucketVersioningCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = s3.get_bucket_versioning(Bucket=bucketName) + versioningCheck = str(response['Status']) + print(versioningCheck) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-versioning-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.3] S3 Buckets should have versioning enabled', + 'Description': 'S3 bucket ' + bucketName + ' has versioning enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Versioning and how to configure it refer to the Using Versioning section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'Status'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-versioning-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'LOW' }, + 'Confidence': 99, + 'Title': '[S3.3] S3 Buckets should have versioning enabled', + 'Description': 'S3 bucket ' + bucketName + ' does not have versioning enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Versioning and how to configure it refer to the Using Versioning section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/Versioning.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF ID.BE-5', + 'NIST CSF PR.PT-5', + 'NIST SP 800-53 CP-2', + 'NIST SP 800-53 CP-11', + 'NIST SP 800-53 SA-13', + 'NIST SP 800-53 SA14', + 'AICPA TSC CC3.1', + 'AICPA TSC A1.2', + 'ISO 27001:2013 A.11.1.4', + 'ISO 27001:2013 A.17.1.1', + 'ISO 27001:2013 A.17.1.2', + 'ISO 27001:2013 A.17.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class BucketPolicyAllowsPublicAccessCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = s3.get_bucket_policy(Bucket=bucketName) + try: + response = s3.get_bucket_policy_status(Bucket=bucketName) + publicBucketPolicyCheck = str(response['PolicyStatus']['IsPublic']) + if publicBucketPolicyCheck != 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-policy-allows-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'CRITICAL' }, + 'Confidence': 99, + 'Title': '[S3.4] S3 Bucket Policies should not allow public access to the bucket', + 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy attached that allows public access. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-policy-allows-public-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.4] S3 Bucket Policies should not allow public access to the bucket', + 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy attached and it does not allow public access.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + print(e) + except Exception as e: + print('This bucket does not have a bucket policy and the status cannot be checked') + pass + +class BucketPolicyCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = s3.get_bucket_policy(Bucket=bucketName) + print('This bucket has a policy but we wont be printing that in the logs lol') + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-policy-exists-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.5] S3 Buckets should have a bucket policy configured', + 'Description': 'S3 bucket ' + bucketName + ' has a bucket policy configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == 'An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-policy-exists-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[S3.5] S3 Buckets should have a bucket policy configured', + 'Description': 'S3 bucket ' + bucketName + ' does not have a bucket policy configured. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Bucket Policy Examples section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class BucketAccessLoggingCheck(Auditor): + def execute(self): + for buckets in myS3Buckets: + bucketName = str(buckets['Name']) + s3Arn = 'arn:aws:s3:::' + bucketName + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + response = s3.get_bucket_logging(Bucket=bucketName) + accessLoggingCheck = str(response['LoggingEnabled']) + # this is a passing check + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-server-access-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.6] S3 Buckets should have server access logging enabled', + 'Description': 'S3 bucket ' + bucketName + ' does not have server access logging enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Amazon S3 Server Access Logging section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except Exception as e: + if str(e) == "'LoggingEnabled'": + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': s3Arn + '/s3-bucket-server-access-logging-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': s3Arn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[S3.6] S3 Buckets should have server access logging enabled', + 'Description': 'S3 bucket ' + bucketName + ' does not have server access logging enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Bucket Policies and how to configure it refer to the Amazon S3 Server Access Logging section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsS3Bucket', + 'Id': s3Arn, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + print(e) + +class S3AccountLevelBlock(Auditor): + def execute(self): + response = s3control.get_public_access_block(AccountId=awsAccountId) + accountBlock = response['PublicAccessBlockConfiguration'] + blockAcl = str(accountBlock['BlockPublicAcls']) + ignoreAcl = str(accountBlock['IgnorePublicAcls']) + blockPubPolicy = str(accountBlock['BlockPublicPolicy']) + restrictPubBuckets = str(accountBlock['RestrictPublicBuckets']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if blockAcl and ignoreAcl and blockPubPolicy and restrictPubBuckets == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/s3-account-level-public-access-block-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': awsAccountId, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[S3.7] Account-level S3 public access block should be configured', + 'Description': 'Account-level S3 public access block for account ' + awsAccountId + ' is enabled', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Account level S3 public access block and how to configure it refer to the Using Amazon S3 Block Public Access section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': awsAccountId + '/s3-account-level-public-access-block-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': awsAccountId, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[S3.7] Account-level S3 public access block should be configured', + 'Description': 'Account-level S3 public access block for account ' + awsAccountId + ' is either inactive or is not block all possible scenarios. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on Account level S3 public access block and how to configure it refer to the Using Amazon S3 Block Public Access section of the Amazon Simple Storage Service Developer Guide', + 'Url': 'https://docs.aws.amazon.com/AmazonS3/latest/dev/access-control-block-public-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'AwsAccount', + 'Id': 'AWS::::Account:' + awsAccountId, + 'Partition': 'aws', + 'Region': awsRegion + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-3', + 'NIST SP 800-53 AC-1', + 'NIST SP 800-53 AC-17', + 'NIST SP 800-53 AC-19', + 'NIST SP 800-53 AC-20', + 'NIST SP 800-53 SC-15', + 'AICPA TSC CC6.6', + 'ISO 27001:2013 A.6.2.1', + 'ISO 27001:2013 A.6.2.2', + 'ISO 27001:2013 A.11.2.6', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.2.1' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding diff --git a/eeauditor/auditors/Amazon_SageMaker_Auditor.py b/eeauditor/auditors/Amazon_SageMaker_Auditor.py new file mode 100644 index 00000000..f00b2ebc --- /dev/null +++ b/eeauditor/auditors/Amazon_SageMaker_Auditor.py @@ -0,0 +1,662 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor +# import boto3 clients +sts = boto3.client('sts') +sagemaker = boto3.client('sagemaker') +# create env vars +awsRegion = os.environ['AWS_REGION'] +awsAccountId = sts.get_caller_identity()['Account'] + +class SagemakerNotebookEncryptionCheck(Auditor): + def execute(self): + # loop through sagemaker notebooks + response = sagemaker.list_notebook_instances() + mySageMakerNotebooks = response['NotebookInstances'] + for notebooks in mySageMakerNotebooks: + notebookName = str(notebooks['NotebookInstanceName']) + response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) + notebookArn = str(response['NotebookInstanceArn']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + notebookEncryptionCheck = str(response['KmsKeyId']) + print(notebookEncryptionCheck) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SageMaker.1] SageMaker notebook instance storage volumes should be encrypted', + 'Description': 'SageMaker notebook instance ' + notebookName + ' is encrypted.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[SageMaker.1] SageMaker notebook instance storage volumes should be encrypted', + 'Description': 'SageMaker notebook instance ' + notebookName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class SagemakerNotebookDirectInternetAccessCheck(Auditor): + def execute(self): + # loop through sagemaker notebooks + response = sagemaker.list_notebook_instances() + mySageMakerNotebooks = response['NotebookInstances'] + for notebooks in mySageMakerNotebooks: + notebookName = str(notebooks['NotebookInstanceName']) + response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) + notebookArn = str(response['NotebookInstanceArn']) + directInternetCheck = str(response['DirectInternetAccess']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if directInternetCheck == 'Enabled': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-direct-internet-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[SageMaker.2] SageMaker notebook instances should not have direct internet access configured', + 'Description': 'SageMaker notebook instance ' + notebookName + ' has direct internet access configured. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-direct-internet-access-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SageMaker.2] SageMaker notebook instances should not have direct internet access configured', + 'Description': 'SageMaker notebook instance ' + notebookName + ' does not have direct internet access configured.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class SagemakerNotebookInVPCCheck(Auditor): + def execute(self): + # loop through sagemaker notebooks + response = sagemaker.list_notebook_instances() + mySageMakerNotebooks = response['NotebookInstances'] + for notebooks in mySageMakerNotebooks: + notebookName = str(notebooks['NotebookInstanceName']) + response = sagemaker.describe_notebook_instance(NotebookInstanceName=notebookName) + notebookArn = str(response['NotebookInstanceArn']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + inVpcCheck = str(response['SubnetId']) + print(inVpcCheck) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-in-vpc-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SageMaker.3] SageMaker notebook instances should be placed in a VPC', + 'Description': 'SageMaker notebook instance ' + notebookName + ' is not in a VPC. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': notebookArn + '/sagemaker-notebook-in-vpc-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': notebookArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SageMaker.3] SageMaker notebook instances should be placed in a VPC', + 'Description': 'SageMaker notebook instance ' + notebookName + ' is in a VPC.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker infrastructure protection refer to the Connect a Notebook Instance to Resources in a VPC section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/appendix-notebook-and-internet-access.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': notebookArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'notebookName': notebookName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class SagemakerEndpointEncryptionCheck(Auditor): + def execute(self): + # loop through sagemaker endpoints + response = sagemaker.list_endpoints() + mySageMakerEndpoints = response['Endpoints'] + for endpoints in mySageMakerEndpoints: + endpointName = str(endpoints['EndpointName']) + response = sagemaker.describe_endpoint(EndpointName=endpointName) + endpointArn = str(response['EndpointArn']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + try: + dataCaptureEncryptionCheck = str(response['DataCaptureConfig']['KmsKeyId']) + print(dataCaptureEncryptionCheck) + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': endpointArn + '/sagemaker-endpoint-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': endpointArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SageMaker.4] SageMaker endpoints should be encrypted', + 'Description': 'SageMaker endpoint ' + endpointName + ' is encrypted.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': endpointArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'endpointName': endpointName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + except: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': endpointArn + '/sagemaker-endpoint-encryption-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': endpointArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'HIGH' }, + 'Confidence': 99, + 'Title': '[SageMaker.4] SageMaker endpoints should be encrypted', + 'Description': 'SageMaker endpoint ' + endpointName + ' is not encrypted. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker encryption and how to configure it refer to the Protect Data at Rest Using Encryption section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/encryption-at-rest.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': endpointArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'endpointName': endpointName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.DS-1', + 'NIST SP 800-53 MP-8', + 'NIST SP 800-53 SC-12', + 'NIST SP 800-53 SC-28', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.8.2.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + +class SagemakerModelNetworkIsolationCheck(Auditor): + def execute(self): + # loop through sagemaker models + response = sagemaker.list_models() + mySageMakerModels = response['Models'] + for models in mySageMakerModels: + modelName = str(models['ModelName']) + modelArn = str(models['ModelArn']) + response = sagemaker.describe_model(ModelName=modelName) + networkIsolationCheck = str(response['EnableNetworkIsolation']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if networkIsolationCheck == 'False': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': modelArn + '/sagemaker-model-network-isolation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': modelArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[SageMaker.5] SageMaker models should have network isolation enabled', + 'Description': 'SageMaker model ' + modelName + ' does not have network isolation enabled. Refer to the remediation instructions to remediate this behavior', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker model network isolation and how to configure it refer to the Training and Inference Containers Run in Internet-Free Mode section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/mkt-algo-model-internet-free.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': modelArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'modelName': modelName + } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': modelArn + '/sagemaker-model-network-isolation-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': modelArn, + 'AwsAccountId': awsAccountId, + 'Types': [ + 'Software and Configuration Checks/AWS Security Best Practices', + 'Effects/Data Exposure' + ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[SageMaker.5] SageMaker models should have network isolation enabled', + 'Description': 'SageMaker model ' + modelName + ' has network isolation enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on SageMaker model network isolation and how to configure it refer to the Training and Inference Containers Run in Internet-Free Mode section of the Amazon SageMaker Developer Guide', + 'Url': 'https://docs.aws.amazon.com/sagemaker/latest/dg/mkt-algo-model-internet-free.html' + } + }, + 'ProductFields': { 'Product Name': 'ElectricEye' }, + 'Resources': [ + { + 'Type': 'Other', + 'Id': modelArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { + 'modelName': modelName + } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/Amazon_Shield_Advanced_Auditor.py b/eeauditor/auditors/Amazon_Shield_Advanced_Auditor.py new file mode 100644 index 00000000..a5789bce --- /dev/null +++ b/eeauditor/auditors/Amazon_Shield_Advanced_Auditor.py @@ -0,0 +1,1222 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +shield = boto3.client("shield") +route53 = boto3.client("route53") +elbclassic = boto3.client("elb") +elbv2 = boto3.client("elbv2") +ec2 = boto3.client("ec2") +cloudfront = boto3.client("cloudfront") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +if awsRegion != "us-east-1": + print("Shield Advanced APIs are only available in North Virginia") +else: + + class ShieldAdvancedRoute53ProtectionCheck(Auditor): + def execute(self): + response = route53.list_hosted_zones() + for hostedzone in response["HostedZones"]: + rawHzId = str(hostedzone["Id"]) + hostedZoneId = rawHzId.replace("/hostedzone/", "") + hostedZoneArn = "arn:aws:route53:::hostedzone/" + hostedZoneId + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + response = shield.describe_protection(ResourceArn=hostedZoneArn) + finding = { + "SchemaVersion": "2018-10-08", + "Id": hostedZoneArn + "/route53-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": hostedZoneArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.1] Route 53 Hosted Zones should be protected by Shield Advanced", + "Description": "Route53 Hosted Zone " + + hostedZoneId + + " is protected by Shield Advanced.", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRoute53HostedZone", + "Id": hostedZoneArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"hostedZoneId": hostedZoneId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if ( + str(e) + == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": hostedZoneArn + + "/route53-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": hostedZoneArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.1] Route 53 Hosted Zones should be protected by Shield Advanced", + "Description": "Route53 Hosted Zone " + + hostedZoneId + + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRoute53HostedZone", + "Id": hostedZoneArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"hostedZoneId": hostedZoneId} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + class ShieldAdvancedELBProtectionCheck(Auditor): + def execute(self): + response = elbclassic.describe_load_balancers() + for classicbalancer in response["LoadBalancerDescriptions"]: + clbName = str(classicbalancer["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + response = shield.describe_protection(ResourceArn=clbArn) + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classiclb-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.2] Classic Load Balancers should be protected by Shield Advanced", + "Description": "Classic Load Balancer " + + clbName + + " is protected by Shield Advanced.", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if ( + str(e) + == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + "/classiclb-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.2] Classic Load Balancers should be protected by Shield Advanced", + "Description": "Classic Load Balancer " + + clbName + + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + class ShieldAdvancedELBV2ProtectionCheck(Auditor): + def execute(self): + response = elbv2.describe_load_balancers() + for loadbalancer in response["LoadBalancers"]: + elbv2Name = str(loadbalancer["LoadBalancerName"]) + elbv2Arn = str(loadbalancer["LoadBalancerArn"]) + elbv2DnsName = str(loadbalancer["DNSName"]) + elbv2LbType = str(loadbalancer["Type"]) + elbv2Scheme = str(loadbalancer["Scheme"]) + elbv2VpcId = str(loadbalancer["VpcId"]) + elbv2IpAddressType = str(loadbalancer["IpAddressType"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + response = shield.describe_protection(ResourceArn=elbv2Arn) + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.3] ELBv2 Load Balancers should be protected by Shield Advanced", + "Description": "ELBv2 " + + elbv2LbType + + " load balancer " + + elbv2Name + + " is protected by Shield Advanced.", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if ( + str(e) + == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/elbv2-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.3] ELBv2 Load Balancers should be protected by Shield Advanced", + "Description": "ELBv2 " + + elbv2LbType + + " load balancer " + + elbv2Name + + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2DnsName, + "IpAddressType": elbv2IpAddressType, + "Scheme": elbv2Scheme, + "Type": elbv2LbType, + "VpcId": elbv2VpcId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + class ShieldAdvancedEIPProtectionCheck(Auditor): + def execute(self): + response = ec2.describe_addresses() + for elasticip in response["Addresses"]: + # arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:eip/${EIP1.AllocationId} + allocationId = str(elasticip["AllocationId"]) + eipAllocationArn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + ":eip-allocation/" + + allocationId + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + response = shield.describe_protection(ResourceArn=eipAllocationArn) + finding = { + "SchemaVersion": "2018-10-08", + "Id": eipAllocationArn + + "/elasticip-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": eipAllocationArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.4] Elastic IPs should be protected by Shield Advanced", + "Description": "Elastic IP allocation " + + allocationId + + " is protected by Shield Advanced.", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Eip", + "Id": eipAllocationArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"AllocationId": allocationId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if ( + str(e) + == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": eipAllocationArn + + "/elasticip-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": eipAllocationArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.4] Elastic IPs should be protected by Shield Advanced", + "Description": "Elastic IP allocation " + + allocationId + + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Eip", + "Id": eipAllocationArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"AllocationId": allocationId} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + class ShieldAdvancedCloudfrontProtectionCheck(Auditor): + def execute(self): + response = cloudfront.list_distributions() + cfDistros = response["DistributionList"]["Items"] + for distro in cfDistros: + distroId = str(distro["Id"]) + distroArn = str(distro["ARN"]) + distroDomainName = str(distro["DomainName"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + response = shield.describe_protection(ResourceArn=distroArn) + finding = { + "SchemaVersion": "2018-10-08", + "Id": distroArn + "/cloudfront-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": distroArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.5] CloudFront distributions should be protected by Shield Advanced", + "Description": "CloudFront distribution " + + distroId + + " is protected by Shield Advanced.", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCloudFrontDistribution", + "Id": distroArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCloudFrontDistribution": { + "DomainName": distroDomainName + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + if ( + str(e) + == "An error occurred (ResourceNotFoundException) when calling the DescribeProtection operation: The referenced protection does not exist." + ): + finding = { + "SchemaVersion": "2018-10-08", + "Id": distroArn + "/cloudfront-shield-adv-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": distroArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.5] CloudFront distributions should be protected by Shield Advanced", + "Description": "CloudFront distribution " + + distroId + + " is not protected by Shield Advanced. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "For information on adding Shield Advanced protection to resources refer to the Adding AWS Shield Advanced Protection to AWS Resources section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/configure-new-protection.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsCloudFrontDistribution", + "Id": distroArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsCloudFrontDistribution": { + "DomainName": distroDomainName + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + + class ShieldAdvancedDRTAccessCheck(Auditor): + def execute(self): + response = shield.describe_drt_access() + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + # this is a passing check + drtRole = str(response["RoleArn"]) + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-drt-iam-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.6] The DDoS Response Team (DRT) should be authorized to take action in your account", + "Description": "The Shield Advanced DRT is authorized to take action in Account " + + awsAccountId + + " with the IAM role " + + drtRole, + "Remediation": { + "Recommendation": { + "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-drt-iam-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.6] The DDoS Response Team (DRT) should be authorized to take action in your account", + "Description": "The Shield Advanced DRT is not authorized to take action in Account " + + awsAccountId + + " . Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + class ShieldAdvancedDRTs3bucketCheck(Auditor): + def execute(self): + response = shield.describe_drt_access() + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + logBucketList = str(response["LogBucketList"]) + print(logBucketList) + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-drt-s3bucket-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.7] The DDoS Response Team (DRT) should be authorized to view your AWS Web Application Firewall (WAF) logging buckets", + "Description": "The Shield Advanced DRT is authorized to view one or more WAF log S3 buckets in " + + awsAccountId, + "Remediation": { + "Recommendation": { + "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-drt-s3bucket-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.7] The DDoS Response Team (DRT) should be authorized to view your AWS Web Application Firewall (WAF) logging buckets", + "Description": "The Shield Advanced DRT is not authorized to view any WAF log S3 buckets in " + + awsAccountId + + " . Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "For information on authorizing the DRT refer to the Authorize the DDoS Response Team section of the AWS WAF, AWS Firewall Manager, and AWS Shield Advanced Developer Guide", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/authorize-DRT.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-6", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-2", + "NIST SP 800-53 AC-3", + "NIST SP 800-53 AC-16", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-24", + "NIST SP 800-53 IA-1", + "NIST SP 800-53 IA-2", + "NIST SP 800-53 IA-4", + "NIST SP 800-53 IA-5", + "NIST SP 800-53 IA-8", + "NIST SP 800-53 PE-2", + "NIST SP 800-53 PS-3", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.7.1.1", + "ISO 27001:2013 A.9.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + class ShieldAdvancedSubscriptionAutorenewCheck(Auditor): + def execute(self): + response = shield.describe_subscription() + renewCheck = str(response["Subscription"]["AutoRenew"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if renewCheck != "ENABLED": + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-subscription-auto-renew-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.8] Shield Advanced subscription should be set to auto-renew", + "Description": "The Shield Advanced subscription for " + + awsAccountId + + " is not set to auto-renew. Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "To update the subscription renewel use the UpdateSubscription API, refer to the link for more details.", + "Url": "https://docs.aws.amazon.com/waf/latest/DDOSAPIReference/API_UpdateSubscription.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": awsAccountId + "/shield-adv-subscription-auto-renew-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": awsAccountId, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[ShieldAdvanced.8] Shield Advanced subscription should be set to auto-renew", + "Description": "The Shield Advanced subscription for " + + awsAccountId + + " is set to auto-renew", + "Remediation": { + "Recommendation": { + "Text": "To update the subscription renewel use the UpdateSubscription API, refer to the link for more details.", + "Url": "https://docs.aws.amazon.com/waf/latest/DDOSAPIReference/API_UpdateSubscription.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsAccount", + "Id": "AWS::::Account:" + awsAccountId, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Amazon_VPC_Auditor.py b/eeauditor/auditors/Amazon_VPC_Auditor.py new file mode 100644 index 00000000..cbd09826 --- /dev/null +++ b/eeauditor/auditors/Amazon_VPC_Auditor.py @@ -0,0 +1,277 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +import os +from auditors.Auditor import Auditor +# create boto3 clients +sts = boto3.client('sts') +ec2 = boto3.client('ec2') +# create env vars +awsAccountId = sts.get_caller_identity()['Account'] +#awsRegion = os.environ['AWS_REGION'] +awsRegion = 'us-east-1' +# loop through vpcs +response = ec2.describe_vpcs(DryRun=False) +myVpcs = response['Vpcs'] + +class vpcDefaultCheck(Auditor): + def execute(self): + for vpcs in myVpcs: + vpcId = str(vpcs['VpcId']) + vpcArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + 'vpc/' + vpcId + defaultVpcCheck = str(vpcs['IsDefault']) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if defaultVpcCheck == 'True': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': vpcArn + '/vpc-is-default-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': vpcArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[VPC.1] Consider deleting the Default VPC if unused', + 'Description': 'VPC ' + vpcId + ' has been identified as the Default VPC, consider deleting this VPC if it is not necessary for daily operations. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on the default VPC refer to the Deleting Your Default Subnets and Default VPC section of the Amazon Virtual Private Cloud User Guide', + 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#deleting-default-vpc' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Vpc', + 'Id': vpcArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'vpcId': vpcId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': vpcArn + '/vpc-is-default-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': vpcArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[VPC.1] Consider deleting the Default VPC if unused', + 'Description': 'VPC ' + vpcId + ' is not the Default VPC', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on the default VPC refer to the Deleting Your Default Subnets and Default VPC section of the Amazon Virtual Private Cloud User Guide', + 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html#deleting-default-vpc' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Vpc', + 'Id': vpcArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'vpcId': vpcId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF PR.AC-5', + 'NIST SP 800-53 AC-4', + 'NIST SP 800-53 AC-10', + 'NIST SP 800-53 SC-7', + 'AICPA TSC CC6.1', + 'ISO 27001:2013 A.13.1.1', + 'ISO 27001:2013 A.13.1.3', + 'ISO 27001:2013 A.13.2.1', + 'ISO 27001:2013 A.14.1.2', + 'ISO 27001:2013 A.14.1.3' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding + +class vpcFlowLogsCheck(Auditor): + def execute(self): + for vpcs in myVpcs: + vpcId = str(vpcs['VpcId']) + vpcArn = 'arn:aws:ec2:' + awsRegion + ':' + awsAccountId + 'vpc/' + vpcId + response = ec2.describe_flow_logs( + DryRun=False, + Filters=[ + { + 'Name': 'resource-id', + 'Values': [ vpcId ] + } + ] + ) + iso8601Time = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat() + if str(response['FlowLogs']) == '[]': + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': vpcArn + '/vpc-flow-log-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': vpcArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'MEDIUM' }, + 'Confidence': 99, + 'Title': '[VPC.2] Flow Logs should be enabled for all VPCs', + 'Description': 'VPC ' + vpcId + ' does not have flow logging enabled. Refer to the remediation instructions if this configuration is not intended', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on flow logs refer to the VPC Flow Logs section of the Amazon Virtual Private Cloud User Guide', + 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Vpc', + 'Id': vpcArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'vpcId': vpcId } + } + } + ], + 'Compliance': { + 'Status': 'FAILED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'NEW' + }, + 'RecordState': 'ACTIVE' + } + yield finding + else: + finding = { + 'SchemaVersion': '2018-10-08', + 'Id': vpcArn + '/vpc-flow-log-check', + 'ProductArn': 'arn:aws:securityhub:' + awsRegion + ':' + awsAccountId + ':product/' + awsAccountId + '/default', + 'GeneratorId': vpcArn, + 'AwsAccountId': awsAccountId, + 'Types': [ 'Software and Configuration Checks/AWS Security Best Practices' ], + 'FirstObservedAt': iso8601Time, + 'CreatedAt': iso8601Time, + 'UpdatedAt': iso8601Time, + 'Severity': { 'Label': 'INFORMATIONAL' }, + 'Confidence': 99, + 'Title': '[VPC.2] Flow Logs should be enabled for all VPCs', + 'Description': 'VPC ' + vpcId + ' has flow logging enabled.', + 'Remediation': { + 'Recommendation': { + 'Text': 'For more information on flow logs refer to the VPC Flow Logs section of the Amazon Virtual Private Cloud User Guide', + 'Url': 'https://docs.aws.amazon.com/vpc/latest/userguide/flow-logs.html' + } + }, + 'ProductFields': { + 'Product Name': 'ElectricEye' + }, + 'Resources': [ + { + 'Type': 'AwsEc2Vpc', + 'Id': vpcArn, + 'Partition': 'aws', + 'Region': awsRegion, + 'Details': { + 'Other': { 'vpcId': vpcId } + } + } + ], + 'Compliance': { + 'Status': 'PASSED', + 'RelatedRequirements': [ + 'NIST CSF DE.AE-3', + 'NIST SP 800-53 AU-6', + 'NIST SP 800-53 CA-7', + 'NIST SP 800-53 IR-4', + 'NIST SP 800-53 IR-5', + 'NIST SP 800-53 IR-8', + 'NIST SP 800-53 SI-4', + 'AICPA TSC CC7.2', + 'ISO 27001:2013 A.12.4.1', + 'ISO 27001:2013 A.16.1.7' + ] + }, + 'Workflow': { + 'Status': 'RESOLVED' + }, + 'RecordState': 'ARCHIVED' + } + yield finding diff --git a/eeauditor/auditors/Amazon_WorkSpaces_Auditor.py b/eeauditor/auditors/Amazon_WorkSpaces_Auditor.py new file mode 100644 index 00000000..d553cb14 --- /dev/null +++ b/eeauditor/auditors/Amazon_WorkSpaces_Auditor.py @@ -0,0 +1,596 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import os +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +workspaces = boto3.client("workspaces") +# create env vars +awsRegion = os.environ["AWS_REGION"] +awsAccountId = sts.get_caller_identity()["Account"] +# loop through workspaces +try: + response = workspaces.describe_workspaces() + myWorkSpaces = response["Workspaces"] +except: + response = "" + myWorkSpaces = "" + + +class WorkspacesUserVolumeEncryptionCheck(Auditor): + def execute(self): + for workspace in myWorkSpaces: + workspaceId = str(workspace["WorkspaceId"]) + workspaceArn = ( + "arn:aws:workspaces:" + + awsRegion + + ":" + + awsAccountId + + ":workspace/" + + workspaceId + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + userVolumeEncryptionCheck = str( + workspace["UserVolumeEncryptionEnabled"] + ) + if userVolumeEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-user-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[WorkSpaces.1] WorkSpaces should have user volume encryption enabled", + "Description": "Workspace " + + workspaceId + + " does not have user volume encryption enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-user-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[WorkSpaces.1] WorkSpaces should have user volume encryption enabled", + "Description": "Workspace " + + workspaceId + + " has user volume encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class WorkspacesRootVolumeEncryptionCheck(Auditor): + def execute(self): + for workspace in myWorkSpaces: + workspaceId = str(workspace["WorkspaceId"]) + workspaceArn = ( + "arn:aws:workspaces:" + + awsRegion + + ":" + + awsAccountId + + ":workspace/" + + workspaceId + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + rootVolumeEncryptionCheck = str( + workspace["RootVolumeEncryptionEnabled"] + ) + if rootVolumeEncryptionCheck == "False": + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-root-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[WorkSpaces.1] WorkSpaces should have root volume encryption enabled", + "Description": "Workspace " + + workspaceId + + " does not have root volume encryption enabled. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-root-volume-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[WorkSpaces.1] WorkSpaces should have root volume encryption enabled", + "Description": "Workspace " + + workspaceId + + " does not have root volume encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces encryption and how to configure it refer to the Encrypted WorkSpaces section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/encrypt-workspaces.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +class WorkspacesRunningModeCheck(Auditor): + def execute(self): + for workspace in myWorkSpaces: + workspaceId = str(workspace["WorkspaceId"]) + workspaceArn = ( + "arn:aws:workspaces:" + + awsRegion + + ":" + + awsAccountId + + ":workspace/" + + workspaceId + ) + runningModeCheck = str(workspace["WorkspaceProperties"]["RunningMode"]) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if runningModeCheck != "AUTO_STOP": + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-auto-stop-running-mode-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[WorkSpaces.3] WorkSpaces should be configured to auto stop after inactivity", + "Description": "Workspace " + + workspaceId + + " does not have its running mode configured to auto-stop. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces running modes and how to auto-stop refer to the Manage the WorkSpace Running Mode section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/running-mode.html#stop-start-workspace", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspaceArn + "/workspaces-auto-stop-running-mode-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspaceArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[WorkSpaces.3] WorkSpaces should be configured to auto stop after inactivity", + "Description": "Workspace " + + workspaceId + + " has its running mode configured to auto-stop.", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces running modes and how to auto-stop refer to the Manage the WorkSpace Running Mode section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.aws.amazon.com/workspaces/latest/adminguide/running-mode.html#stop-start-workspace", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsWorkspacesWorkspace", + "Id": workspaceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"WorkspaceId": workspaceId}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +class WorkspacesDirectoryDefaultInternetCheck(Auditor): + def execute(self): + response = workspaces.describe_workspace_directories() + for directory in response["Directories"]: + workspacesDirectoryId = str(directory["DirectoryId"]) + workspacesDirectoryArn = ( + "arn:aws:workspaces:" + + awsRegion + + ":" + + awsAccountId + + ":directory/" + + workspacesDirectoryId + ) + internetAccessCheck = str( + directory["WorkspaceCreationProperties"]["EnableInternetAccess"] + ) + iso8601Time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if internetAccessCheck == "True": + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspacesDirectoryArn + + "/workspaces-directory-default-internet-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspacesDirectoryArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "MEDIUM"}, + "Confidence": 99, + "Title": "[WorkSpaces.4] WorkSpaces Directories should not be configured to provide default internet access", + "Description": "Workspace directory " + + workspacesDirectoryId + + " provides default internet access to WorkSpaces. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces internet access refer to the Provide Internet Access from Your WorkSpace section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.amazonaws.cn/en_us/workspaces/latest/adminguide/amazon-workspaces-internet-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": workspacesDirectoryArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"DirectoryId": workspacesDirectoryId} + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": workspacesDirectoryArn + + "/workspaces-directory-default-internet-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": workspacesDirectoryArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[WorkSpaces.4] WorkSpaces Directories should not be configured to provide default internet access", + "Description": "Workspace directory " + + workspacesDirectoryId + + " does not provide default internet access to WorkSpaces.", + "Remediation": { + "Recommendation": { + "Text": "For more information on WorkSpaces internet access refer to the Provide Internet Access from Your WorkSpace section of the Amazon WorkSpaces Administrator Guide", + "Url": "https://docs.amazonaws.cn/en_us/workspaces/latest/adminguide/amazon-workspaces-internet-access.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "Other", + "Id": workspacesDirectoryArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": {"DirectoryId": workspacesDirectoryId} + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-5", + "NIST SP 800-53 AC-4", + "NIST SP 800-53 AC-10", + "NIST SP 800-53 SC-7", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.1.3", + "ISO 27001:2013 A.13.2.1", + "ISO 27001:2013 A.14.1.2", + "ISO 27001:2013 A.14.1.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding diff --git a/eeauditor/auditors/Auditor.py b/eeauditor/auditors/Auditor.py new file mode 100644 index 00000000..1f939ba1 --- /dev/null +++ b/eeauditor/auditors/Auditor.py @@ -0,0 +1,77 @@ +"""Auditor plugin manager + +This module implements a plugin manager for ElectricEye auditors. It consists of two parts: + The base Auditor class that ever auditor check must inherit from + The AuditorCollection that loads the plugins from the plugin directory + +Example usage: + Create a list of auditor checks by passing the relative package name where the plugins reside: + auditors = AuditorCollection("auditors") + This will return a list of dictionaries: + { + "check": , + "auditor": + } +""" + +import inspect +import os +import pkgutil +import importlib + + +class Auditor(object): + """Base class that each auditor must inherit from. + Every auditor must implement an execute method. + """ + + def __init__(self): + self.description = "UNKNOWN" + self.name = self.__class__.__name__ + + def execute(self, *args, **kwargs): + """The method that we expect all plugins to implement. This is the + method that our framework will call + """ + raise NotImplementedError + + +class AuditorCollection(object): + """Upon creation, this class will read the plugins package for modules + that contain a class definition that is inheriting from the Auditor class + """ + + def __init__(self, plugin_package): + """Constructor that initiates the reading of all available plugins + when an instance of the PluginCollection object is created + """ + self.plugin_package = plugin_package + self.reload_plugins() + + def reload_plugins(self): + """Reset the list of all plugins and initiate the walk over the main + provided plugin package to load all available plugins + """ + self.plugins = [] + self.walk_package(self.plugin_package) + + def walk_package(self, package): + """Load all modules in package to retrieve all plugins + """ + imported_package = __import__(package) + + for _, pluginname, ispkg in pkgutil.iter_modules( + imported_package.__path__, imported_package.__name__ + "." + ): + try: + if not ispkg: + plugin_module = importlib.import_module(pluginname) + clsmembers = inspect.getmembers(plugin_module, inspect.isclass) + for (_, c) in clsmembers: + # Only add classes that are a sub class of Auditor, but NOT Auditor itself + if issubclass(c, Auditor) & (c is not Auditor): + self.plugins.append( + {"check": c(), "auditor": pluginname,} + ) + except Exception as e: + print(f"failed to load {pluginname} with error {e}") diff --git a/eeauditor/auditors/Shodan_Auditor.py b/eeauditor/auditors/Shodan_Auditor.py new file mode 100644 index 00000000..c31a6184 --- /dev/null +++ b/eeauditor/auditors/Shodan_Auditor.py @@ -0,0 +1,1294 @@ +import boto3 +import os +import requests +import socket +import json +import datetime +from auditors.Auditor import Auditor + +# import boto3 clients +sts = boto3.client("sts") +ssm = boto3.client("ssm") +ec2 = boto3.client("ec2") +elbv2 = boto3.client("elbv2") +rds = boto3.client("rds") +elasticsearch = boto3.client("es") +elb = boto3.client("elb") +dms = boto3.client("dms") +amzmq = boto3.client("mq") + +# create env vars +awsAccountId = sts.get_caller_identity()["Account"] +awsRegion = os.environ["AWS_REGION"] +try: + apiKeyParam = os.environ["SHODAN_API_KEY_PARAM"] +except Exception as e: + apiKeyParam = "" + print(e) + + +# Shodan information for Requests +shodanUrl = "https://api.shodan.io/shodan/host/" +try: + response = ssm.get_parameter(Name=apiKeyParam, WithDecryption=True) + shodanApiKey = str(response["Parameter"]["Value"]) +except Exception as e: + print(e) + + +class PublicEC2ShodanCheck(Auditor): + def execute(self): + try: + response = ec2.describe_instances(DryRun=False, MaxResults=500) + for res in response["Reservations"]: + for inst in res["Instances"]: + ec2Type = str(inst["InstanceType"]) + ec2AmiId = str(inst["ImageId"]) + ec2Id = str(inst["InstanceId"]) + ec2Arn = ( + "arn:aws:ec2:" + + awsRegion + + ":" + + awsAccountId + + "instance/" + + ec2Id + ) + ec2PrivateIp = str(inst["PrivateIpAddress"]) + ec2VpcId = str(inst["VpcId"]) + ec2SubnetId = str(inst["SubnetId"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + ec2PublicIp = str(inst["PublicIpAddress"]) + # use requests Library to check the Shodan index for your host + r = requests.get( + url=shodanUrl + ec2PublicIp + "?key=" + shodanApiKey + ) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": ec2Arn + + "/" + + ec2PublicIp + + "/ec2-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ec2Arn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.EC2.1] EC2 instances with public IP addresses should be monitored for being indexed by Shodan", + "Description": "EC2 instance " + + ec2Id + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": ec2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": ec2Type, + "ImageId": ec2AmiId, + "IpV4Addresses": [ + ec2PublicIp, + ec2PrivateIp, + ], + "VpcId": ec2VpcId, + "SubnetId": ec2SubnetId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": ec2Arn + + "/" + + ec2PublicIp + + "/ec2-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": ec2Arn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.EC2.1] EC2 instances with public IP addresses should be monitored for being indexed by Shodan", + "Description": "EC2 instance " + + ec2Id + + " has been indexed by Shodan on IP address " + + ec2PublicIp + + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your host.", + "SourceUrl": "https://www.shodan.io/host/" + + ec2PublicIp, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": ec2PublicIp, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + + ec2PublicIp, + }, + ], + "Resources": [ + { + "Type": "AwsEc2Instance", + "Id": ec2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsEc2Instance": { + "Type": ec2Type, + "ImageId": ec2AmiId, + "IpV4Addresses": [ + ec2PublicIp, + ec2PrivateIp, + ], + "VpcId": ec2VpcId, + "SubnetId": ec2SubnetId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + if str(e) == "'PublicIpAddress'": + print( + ec2Id + " does not have a Public IPv4 Address, skipping" + ) + pass + else: + print(e) + except Exception as e: + print(e) + + +class PublicALBShodanCheck(Auditor): + def execute(self): + try: + response = elbv2.describe_load_balancers() + for lbs in response["LoadBalancers"]: + elbv2Scheme = str(lbs["Scheme"]) + elbv2Type = str(lbs["Type"]) + elbv2Name = str(lbs["LoadBalancerName"]) + elbv2Arn = str(lbs["LoadBalancerArn"]) + elbv2Vpc = str(lbs["VpcId"]) + elbv2Dns = str(lbs["DNSName"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if elbv2Scheme == "internet-facing" and elbv2Type == "application": + # use Socket to do a DNS lookup and retrieve the IP address + elbv2Ip = socket.gethostbyname(elbv2Dns) + # use requests Library to check the Shodan index for your host + r = requests.get(url=shodanUrl + elbv2Ip + "?key=" + shodanApiKey) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/" + elbv2Dns + "/alb-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.ELBv2.1] Internet-facing Application Load Balancers should be monitored for being indexed by Shodan", + "Description": "ALB " + + elbv2Name + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2Dns, + "Scheme": elbv2Scheme, + "Type": elbv2Type, + "VpcId": elbv2Vpc, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": elbv2Arn + "/" + elbv2Dns + "/alb-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": elbv2Arn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.ELBv2.1] Internet-facing Application Load Balancers should be monitored for being indexed by Shodan", + "Description": "ALB " + + elbv2Name + + " has been indexed by Shodan on IP address " + + elbv2Ip + + " from DNS name " + + elbv2Dns + + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your load balancer.", + "SourceUrl": "https://www.shodan.io/host/" + elbv2Ip, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": elbv2Ip, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + + elbv2Ip, + }, + ], + "Resources": [ + { + "Type": "AwsElbv2LoadBalancer", + "Id": elbv2Arn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElbv2LoadBalancer": { + "DNSName": elbv2Dns, + "Scheme": elbv2Scheme, + "Type": elbv2Type, + "VpcId": elbv2Vpc, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print( + elbv2Name + " is not an ALB or is not internet-facing, skipping" + ) + except Exception as e: + print(e) + + +class PublicRDSShodanCheck(Auditor): + def execute(self): + try: + response = rds.describe_db_instances() + for rdsdb in response["DBInstances"]: + rdsInstanceId = str(rdsdb["DBInstanceIdentifier"]) + rdsInstanceArn = str(rdsdb["DBInstanceArn"]) + rdsInstanceClass = str(rdsdb["DBInstanceClass"]) + rdsDbiRescId = str(rdsdb["DbiResourceId"]) + rdsEngine = str(rdsdb["Engine"]) + rdsEngineVersion = str(rdsdb["EngineVersion"]) + rdsDns = str(rdsdb["Endpoint"]["Address"]) + publicCheck = str(rdsdb["PubliclyAccessible"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if publicCheck == "True": + # use Socket to do a DNS lookup and retrieve the IP address + rdsIp = socket.gethostbyname(rdsDns) + # use requests Library to check the Shodan index for your host + r = requests.get(url=shodanUrl + rdsIp + "?key=" + shodanApiKey) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": rdsInstanceArn + + "/" + + rdsDns + + "/rds-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": rdsInstanceArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.RDS.1] Public accessible RDS instances should be monitored for being indexed by Shodan", + "Description": "RDS instance " + + rdsInstanceId + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": rdsInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": rdsInstanceId, + "DBInstanceClass": rdsInstanceClass, + "DbiResourceId": rdsDbiRescId, + "Engine": rdsEngine, + "EngineVersion": rdsEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": rdsInstanceArn + + "/" + + rdsDns + + "/rds-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": rdsInstanceArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.RDS.1] Public accessible RDS instances should be monitored for being indexed by Shodan", + "Description": "RDS instance " + + rdsInstanceId + + " has been indexed by Shodan on IP address " + + rdsIp + + " from DNS name " + + rdsDns + + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your database.", + "SourceUrl": "https://www.shodan.io/host/" + rdsIp, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": rdsIp, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + rdsIp, + }, + ], + "Resources": [ + { + "Type": "AwsRdsDbInstance", + "Id": rdsInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsRdsDbInstance": { + "DBInstanceIdentifier": rdsInstanceId, + "DBInstanceClass": rdsInstanceClass, + "DbiResourceId": rdsDbiRescId, + "Engine": rdsEngine, + "EngineVersion": rdsEngineVersion, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(rdsInstanceId + " is not Publicly Accessible, skipping") + except Exception as e: + print(e) + + +class PublicESDomainShodanCheck(Auditor): + def execute(self): + try: + response = elasticsearch.list_domain_names() + for domain in response["DomainNames"]: + esDomain = str(domain["DomainName"]) + try: + response = elasticsearch.describe_elasticsearch_domain( + DomainName=esDomain + ) + esDomainId = str(response["DomainStatus"]["DomainId"]) + esDomainName = str(response["DomainStatus"]["DomainName"]) + esDomainArn = str(response["DomainStatus"]["ARN"]) + esVersion = str(response["DomainStatus"]["ElasticsearchVersion"]) + esDomainEndpoint = str(response["DomainStatus"]["Endpoint"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + try: + esVpcOptions = str(response["DomainStatus"]["VPCOptions"]) + print(esDomainId + " is in a VPC, skipping") + pass + except Exception as e: + if str(e) == "'VPCOptions'": + # use Socket to do a DNS lookup and retrieve the IP address + esDomainIp = socket.gethostbyname(esDomainEndpoint) + # use requests Library to check the Shodan index for your host + r = requests.get( + url=shodanUrl + esDomainIp + "?key=" + shodanApiKey + ) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": esDomainArn + + "/" + + esDomainEndpoint + + "/elasticsearch-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": esDomainArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.Elasticsearch.1] ElasticSearch Service domains outside of a VPC should be monitored for being indexed by Shodan", + "Description": "ElasticSearch Service domain " + + esDomainName + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": esDomainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": esDomainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "Endpoint": esDomainEndpoint, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": esDomainArn + + "/" + + esDomainEndpoint + + "/elasticsearch-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": esDomainArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.Elasticsearch.1] ElasticSearch Service domains outside of a VPC should be monitored for being indexed by Shodan", + "Description": "ElasticSearch Service domain " + + esDomainName + + " has been indexed by Shodan on IP address " + + esDomainIp + + " from endpoint DNS name " + + esDomainEndpoint + + ". review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your ES domain.", + "SourceUrl": "https://www.shodan.io/host/" + + esDomainIp, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": esDomainIp, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + + esDomainIp, + }, + ], + "Resources": [ + { + "Type": "AwsElasticsearchDomain", + "Id": esDomainArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "AwsElasticsearchDomain": { + "DomainId": esDomainId, + "DomainName": esDomainName, + "ElasticsearchVersion": esVersion, + "Endpoint": esDomainEndpoint, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + print(e) + except Exception as e: + print(e) + except Exception as e: + print(e) + + +class PublicCLBShodanCheck(Auditor): + def execute(self): + try: + response = elb.describe_load_balancers() + for clbs in response["LoadBalancerDescriptions"]: + clbName = str(clbs["LoadBalancerName"]) + clbArn = ( + "arn:aws:elasticloadbalancing:" + + awsRegion + + ":" + + awsAccountId + + ":loadbalancer/" + + clbName + ) + clbDnsName = str(clbs["DNSName"]) + clbScheme = str(clbs["Scheme"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if clbScheme == "internet-facing": + # use Socket to do a DNS lookup and retrieve the IP address + clbIp = socket.gethostbyname(clbDnsName) + # use requests Library to check the Shodan index for your host + r = requests.get(url=shodanUrl + clbIp + "?key=" + shodanApiKey) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + + "/" + + clbDnsName + + "/classic-load-balancer-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.ELB.1] Internet-facing Classic Load Balancers should be monitored for being indexed by Shodan", + "Description": "ElasticSearch Service domain " + + clbName + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": clbArn + + "/" + + clbDnsName + + "/classic-load-balancer-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": clbArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.ELB.1] Internet-facing Classic Load Balancers should be monitored for being indexed by Shodan", + "Description": "CLB " + + clbName + + " has been indexed by Shodan on IP address " + + clbIp + + " from DNS name " + + clbDnsName + + ". Review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your load balancer.", + "SourceUrl": "https://www.shodan.io/host/" + clbIp, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": clbIp, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + clbIp, + }, + ], + "Resources": [ + { + "Type": "AwsElbLoadBalancer", + "Id": clbArn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"Other": {"LoadBalancerName": clbName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + pass + except Exception as e: + print(e) + + +class PublicDMSReplicationInstanceShodanCheck(Auditor): + def execute(self): + try: + response = dms.describe_replication_instances() + for repinstances in response["ReplicationInstances"]: + dmsInstanceId = str(repinstances["ReplicationInstanceIdentifier"]) + dmsInstanceArn = str(repinstances["ReplicationInstanceArn"]) + publicAccessCheck = str(repinstances["PubliclyAccessible"]) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if publicAccessCheck == "True": + dmsPublicIp = str( + repinstances["ReplicationInstancePublicIpAddress"] + ) + # use requests Library to check the Shodan index for your host + r = requests.get( + url=shodanUrl + dmsPublicIp + "?key=" + shodanApiKey + ) + data = r.json() + shodanOutput = str(data) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": dmsInstanceArn + + "/" + + dmsPublicIp + + "/dms-replication-instance-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": dmsInstanceArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.DMS.1] Publicly accessible Database Migration Service (DMS) Replication Instances should be monitored for being indexed by Shodan", + "Description": "DMS Replication Instance " + + dmsInstanceId + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsDmsReplicationInstance", + "Id": dmsInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ReplicationInstanceId": dmsInstanceId + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": dmsInstanceArn + + "/" + + dmsPublicIp + + "/dms-replication-instance-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": dmsInstanceArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.DMS.1] Publicly accessible Database Migration Service (DMS) Replication Instances should be monitored for being indexed by Shodan", + "Description": "DMS Replication Instance " + + dmsInstanceId + + " has been indexed on IP address " + + dmsInstanceId + + " . Review the Shodan.io host information in the SourceUrl or ThreatIntelIndicators.SourceUrl fields for information about what ports and services are exposed and then take action to reduce exposure and harden your replication instance.", + "SourceUrl": "https://www.shodan.io/host/" + dmsPublicIp, + "ProductFields": {"Product Name": "ElectricEye"}, + "ThreatIntelIndicators": [ + { + "Type": "IPV4_ADDRESS", + "Category": "EXPLOIT_SITE", + "Value": dmsPublicIp, + "LastObservedAt": iso8601time, + "Source": "Shodan.io", + "SourceUrl": "https://www.shodan.io/host/" + + dmsPublicIp, + }, + ], + "Resources": [ + { + "Type": "AwsDmsReplicationInstance", + "Id": dmsInstanceArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "ReplicationInstanceId": dmsInstanceId + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + pass + except Exception as e: + print(e) + + +class PublicAmazonmqBrokerShodanCheck(Auditor): + def execute(self): + try: + response = amzmq.list_brokers(MaxResults=100) + myBrokers = response["BrokerSummaries"] + for brokers in myBrokers: + brokerName = str(brokers["BrokerName"]) + try: + response = amzmq.describe_broker(BrokerId=brokerName) + brokerArn = str(response["BrokerArn"]) + brokerId = str(response["BrokerId"]) + publicAccessCheck = str(response["PubliclyAccessible"]) + if publicAccessCheck == "True": + mqInstances = response["BrokerInstances"] + for instance in mqInstances: + mqBrokerIpv4 = str(instance["IpAddress"]) + r = requests.get( + url=shodanUrl + mqBrokerIpv4 + "?key=" + shodanApiKey + ) + data = r.json() + shodanOutput = str(data) + iso8601time = ( + datetime.datetime.utcnow() + .replace(tzinfo=datetime.timezone.utc) + .isoformat() + ) + if ( + shodanOutput + == "{'error': 'No information available for that IP.'}" + ): + # this is a passing check + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + + "/" + + mqBrokerIpv4 + + "/amazon-mq-broker-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "INFORMATIONAL"}, + "Title": "[Shodan.AmazonMQ.1] Publicly accessible Amazon MQ message brokers should be monitored for being indexed by Shodan", + "Description": "Amazon MQ message brokers " + + brokerName + + " has not been indexed by Shodan.", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": brokerArn + + "/" + + mqBrokerIpv4 + + "/amazon-mq-broker-shodan-index-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": brokerArn, + "AwsAccountId": awsAccountId, + "Types": ["Effects/Data Exposure"], + "CreatedAt": iso8601time, + "UpdatedAt": iso8601time, + "Severity": {"Label": "MEDIUM"}, + "Title": "[Shodan.AmazonMQ.1] Publicly accessible Amazon MQ message brokers should be monitored for being indexed by Shodan", + "Description": "Amazon MQ message brokers " + + brokerName + + " has been indexed by Shodan on IP address " + + mqBrokerIpv4 + + ".", + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsMqMessageBroker", + "Id": brokerArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "brokerName": brokerName, + "brokerId": brokerId, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.RA-2", + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 PM-15", + "NIST SP 800-53 PM-16", + "NIST SP 800-53 SI-4", + "NIST SP 800-53 SI-5", + "AIPCA TSC CC3.2", + "AIPCA TSC CC7.2", + "ISO 27001:2013 A.6.1.4", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + pass + except Exception as e: + print(e) + except Exception as e: + print(e) diff --git a/eeauditor/auditors/aws/AWS_Lambda_Auditor.py b/eeauditor/auditors/aws/AWS_Lambda_Auditor.py new file mode 100644 index 00000000..315a158d --- /dev/null +++ b/eeauditor/auditors/aws/AWS_Lambda_Auditor.py @@ -0,0 +1,166 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +from dateutil import parser +from check_register import CheckRegister + +registry = CheckRegister() +lambda_client = boto3.client("lambda") +cloudwatch = boto3.client("cloudwatch") + + +@registry.register_check("lambda") +def unused_function_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + response = lambda_client.list_functions() + functions = response["Functions"] + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + # create env vars + for function in functions: + functionName = str(function["FunctionName"]) + lambdaArn = str(function["FunctionArn"]) + metricResponse = cloudwatch.get_metric_data( + MetricDataQueries=[ + { + "Id": "m1", + "MetricStat": { + "Metric": { + "Namespace": "AWS/Lambda", + "MetricName": "Invocations", + "Dimensions": [{"Name": "FunctionName", "Value": functionName},], + }, + "Period": 300, + "Stat": "Sum", + }, + } + ], + StartTime=datetime.datetime.now() - datetime.timedelta(days=30), + EndTime=datetime.datetime.now(), + ) + metrics = metricResponse["MetricDataResults"] + for metric in metrics: + modify_date = parser.parse(function["LastModified"]) + date_delta = datetime.datetime.now(datetime.timezone.utc) - modify_date + if len(metric["Values"]) > 0 or date_delta.days < 30: + finding = { + "SchemaVersion": "2018-10-08", + "Id": lambdaArn + "/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": lambdaArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function " + + functionName + + " has been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsLambda", + "Id": lambdaArn, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": lambdaArn + "/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": lambdaArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function " + + functionName + + " has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsLambda", + "Id": lambdaArn, + "Partition": "aws", + "Region": awsRegion, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding diff --git a/eeauditor/auditors/aws/Amazon_APIGW_Auditor.py b/eeauditor/auditors/aws/Amazon_APIGW_Auditor.py new file mode 100644 index 00000000..4cbd8065 --- /dev/null +++ b/eeauditor/auditors/aws/Amazon_APIGW_Auditor.py @@ -0,0 +1,1006 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import boto3 +import datetime +from check_register import CheckRegister + +registry = CheckRegister() + +# import boto3 clients +apigateway = boto3.client("apigateway") + + +def get_rest_apis(cache): + response = cache.get("get_rest_apis") + if response: + return response + cache["get_rest_apis"] = apigateway.get_rest_apis(limit=500) + return cache["get_rest_apis"] + + +@registry.register_check("apigateway") +def api_gateway_stage_metrics_enabled_check( + cache: dict, awsAccountId: str, awsRegion: str +) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + # is is possible methodSettings is empty indicating metrics are not enabled + try: + metricsCheck = str(apistages["methodSettings"]["*/*"]["metricsEnabled"]) + except KeyError: + metricsCheck = "False" + if metricsCheck == "False": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-metrics-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " does not have CloudWatch metrics enabled. You can monitor API execution by using CloudWatch, which collects and processes raw data from API Gateway into readable, near-real-time metrics. These statistics are recorded for a period of 15 months so you can access historical information and gain a better perspective on how your web application or service is performing. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-metrics-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " has CloudWatch metrics enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +@registry.register_check("apigateway") +def api_gateway_stage_logging_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + # it is possible for methodSettings to be empty indicating logging is Off + try: + loggingCheck = str(apistages["methodSettings"]["*/*"]["loggingLevel"]) + except KeyError: + loggingCheck = "OFF" + if loggingCheck == "OFF": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-api-logging-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " does not have CloudWatch API Logging enabled. To help debug issues related to request execution or client access to your API, you can enable Amazon CloudWatch Logs to log API calls. The logged data includes errors or execution traces (such as request or response parameter values or payloads), data used by Lambda authorizers (formerly known as custom authorizers), whether API keys are required, whether usage plans are enabled, and so on. Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-api-logging-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " has CloudWatch API Logging enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +@registry.register_check("apigateway") +def api_gateway_stage_cacheing_enabled_check( + cache: dict, awsAccountId: str, awsRegion: str +) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + # it is possible for methodSettings to be empty which indicated caching is not enabled + try: + cachingCheck = str(apistages["methodSettings"]["*/*"]["cachingEnabled"]) + except KeyError: + cachingCheck = "False" + if cachingCheck == "False": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-caching-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " does not have Caching enabled. You can enable API caching in Amazon API Gateway to cache your endpoints responses. With caching, you can reduce the number of calls made to your endpoint and also improve the latency of requests to your API. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-caching-enabled-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " has Caching enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +@registry.register_check("apigateway") +def api_gateway_stage_cache_encryption_check( + cache: dict, awsAccountId: str, awsRegion: str +) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + try: + cachingEncryptionCheck = str( + apistages["methodSettings"]["*/*"]["cacheDataEncrypted"] + ) + except KeyError: + cachingEncryptionCheck = "False" + if cachingEncryptionCheck == "False": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-cache-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " does not have cache encryption enabled. If you choose to enable caching for a REST API, you can enable cache encryption. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-cache-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " has cache encryption enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +@registry.register_check("apigateway") +def api_gateway_stage_xray_tracking_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + xrayTracingCheck = str(apistages["tracingEnabled"]) + if xrayTracingCheck == "False": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-xray-tracing-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "LOW"}, + "Confidence": 99, + "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " does not have tracing enabled. Because X-Ray gives you an end-to-end view of an entire request, you can analyze latencies in your APIs and their backend services. You can use an X-Ray service map to view the latency of an entire request and that of the downstream services that are integrated with X-Ray. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-xray-tracing-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": ["Software and Configuration Checks/AWS Security Best Practices"], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " has tracing enabled.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + + +@registry.register_check("apigateway") +def api_gateway_stage_waf_check_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for restapi in get_rest_apis(cache)["items"]: + apiGwApiId = str(restapi["id"]) + apiGwApiName = str(restapi["name"]) + response = apigateway.get_stages(restApiId=apiGwApiId) + for apistages in response["item"]: + apiStageName = str(apistages["stageName"]) + apiStageDeploymentId = str(apistages["deploymentId"]) + apiStageArn = ( + "arn:aws:apigateway:" + + awsRegion + + "::/restapis/" + + apiGwApiId + + "/stages/" + + apiStageName + ) + try: + wafCheck = str(apistages["webAclArn"]) + # this is a passing check + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-waf-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " is protected by an AWS WAF Web ACL.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except Exception as e: + print(e) + except Exception as e: + if str(e) == "'webAclArn'": + try: + finding = { + "SchemaVersion": "2018-10-08", + "Id": apiStageArn + "/apigateway-stage-waf-protection-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": apiStageArn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", + "Description": "API Gateway stage " + + apiStageName + + " for Rest API " + + apiGwApiName + + " is not protected by an AWS WAF Web ACL. You can use AWS WAF to protect your API Gateway API from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect API availability and performance, compromise security, or consume excessive resources. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": apiStageArn, + "Partition": "aws", + "Region": awsRegion, + "Details": { + "Other": { + "deploymentId": apiStageDeploymentId, + "stageName": apiStageName, + } + }, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + except Exception as e: + print(e) + else: + print(e) diff --git a/eeauditor/auditors/aws/Amazon_SNS_Auditor.py b/eeauditor/auditors/aws/Amazon_SNS_Auditor.py new file mode 100644 index 00000000..4698aa13 --- /dev/null +++ b/eeauditor/auditors/aws/Amazon_SNS_Auditor.py @@ -0,0 +1,581 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import datetime +import json +import boto3 +from check_register import CheckRegister + +registry = CheckRegister() + +# import boto3 clients +sns = boto3.client("sns") + + +def list_topics(cache): + response = cache.get("list_topics") + if response: + return response + cache["list_topics"] = sns.list_topics() + return cache["list_topics"] + + +@registry.register_check("sns") +def sns_topic_encryption_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + # loop through SNS topics + response = list_topics(cache) + mySnsTopics = response["Topics"] + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for topic in mySnsTopics: + topicarn = str(topic["TopicArn"]) + topicName = topicarn.replace("arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "") + response = sns.get_topic_attributes(TopicArn=topicarn) + try: + # this is a passing check + encryptionCheck = str(response["Attributes"]["KmsMasterKeyId"]) + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-topic-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SNS.1] SNS topics should be encrypted", + "Description": "SNS topic " + topicName + " is encrypted.", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + except: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-topic-encryption-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[SNS.1] SNS topics should be encrypted", + "Description": "SNS topic " + + topicName + + " is not encrypted. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS encryption at rest and how to configure it refer to the Encryption at Rest section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-server-side-encryption.html", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +@registry.register_check("sns") +def sns_http_encryption_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + # loop through SNS topics + response = list_topics(cache) + mySnsTopics = response["Topics"] + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for topic in mySnsTopics: + topicarn = str(topic["TopicArn"]) + topicName = topicarn.replace("arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "") + response = sns.list_subscriptions_by_topic(TopicArn=topicarn) + mySubs = response["Subscriptions"] + for subscriptions in mySubs: + subProtocol = str(subscriptions["Protocol"]) + if subProtocol == "http": + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-http-subscription-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[SNS.2] SNS topics should not use HTTP subscriptions", + "Description": "SNS topic " + + topicName + + " has a HTTP subscriber. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-http-subscription-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SNS.2] SNS topics should not use HTTP subscriptions", + "Description": "SNS topic " + topicName + " does not have a HTTP subscriber.", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS encryption in transit refer to the Enforce Encryption of Data in Transit section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + + +@registry.register_check("sns") +def sns_public_access_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + # loop through SNS topics + response = list_topics(cache) + mySnsTopics = response["Topics"] + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for topic in mySnsTopics: + topicarn = str(topic["TopicArn"]) + topicName = topicarn.replace("arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "") + response = sns.get_topic_attributes(TopicArn=topicarn) + statement_json = response["Attributes"]["Policy"] + statement = json.loads(statement_json) + fail = False + # this results in one finding per topic instead of one finding per statement + for sid in statement["Statement"]: + access = sid["Principal"].get("AWS") + if access != "*" or (access == "*" and "Condition" in sid): + continue + else: + fail = True + break + if not fail: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-public-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 75, # The Condition may not effectively limit access + "Title": "[SNS.3] SNS topics should not have public access", + "Description": "SNS topic " + + topicName + + " does not have public access or limited by a Condition. Refer to the remediation instructions to review sns access policy", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-public-access-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "HIGH"}, + "Confidence": 99, + "Title": "[SNS.3] SNS topics should not have public access", + "Description": "SNS topic " + + topicName + + " has public access. Refer to the remediation instructions to remediate this behavior", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS Access Policy Best Practices refer to Amazons Best Practice rules for Amazon SNS.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#ensure-topics-not-publicly-accessible", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding + + +@registry.register_check("sns") +def sns_cross_account_check(cache: dict, awsAccountId: str, awsRegion: str) -> dict: + # loop through SNS topics + response = list_topics(cache) + mySnsTopics = response["Topics"] + iso8601Time = datetime.datetime.now(datetime.timezone.utc).isoformat() + for topic in mySnsTopics: + topicarn = str(topic["TopicArn"]) + topicName = topicarn.replace("arn:aws:sns:" + awsRegion + ":" + awsAccountId + ":", "") + response = sns.get_topic_attributes(TopicArn=topicarn) + myPolicy_json = str(response["Attributes"]["Policy"]) + myPolicy = json.loads(myPolicy_json) + for statement in myPolicy["Statement"]: + principal = statement["Principal"].get("AWS") + if principal[0] != "*": + if not principal[0].isdigit(): + principal = principal.split(":")[4] + if principal == awsAccountId: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-cross-account-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "INFORMATIONAL"}, + "Confidence": 99, + "Title": "[SNS.4] SNS topics should not allow cross-account access", + "Description": "SNS topic " + + topicName + + " does not have cross-account access.", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS best practices refer to the Amazon SNS security best practices section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "RESOLVED"}, + "RecordState": "ARCHIVED", + } + yield finding + else: + finding = { + "SchemaVersion": "2018-10-08", + "Id": topicarn + "/sns-cross-account-check", + "ProductArn": "arn:aws:securityhub:" + + awsRegion + + ":" + + awsAccountId + + ":product/" + + awsAccountId + + "/default", + "GeneratorId": topicarn, + "AwsAccountId": awsAccountId, + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure", + ], + "FirstObservedAt": iso8601Time, + "CreatedAt": iso8601Time, + "UpdatedAt": iso8601Time, + "Severity": {"Label": "Low"}, + "Confidence": 99, + "Title": "[SNS.4] SNS topics should not allow cross-account access", + "Description": "SNS topic " + topicName + " has cross-account access.", + "Remediation": { + "Recommendation": { + "Text": "For more information on SNS best practices refer to the Amazon SNS security best practices section of the Amazon Simple Notification Service Developer Guide.", + "Url": "https://docs.aws.amazon.com/sns/latest/dg/sns-security-best-practices.html#enforce-encryption-data-in-transit", + } + }, + "ProductFields": {"Product Name": "ElectricEye"}, + "Resources": [ + { + "Type": "AwsSnsTopic", + "Id": topicarn, + "Partition": "aws", + "Region": awsRegion, + "Details": {"AwsSnsTopic": {"TopicName": topicName}}, + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.AC-3", + "NIST SP 800-53 AC-1", + "NIST SP 800-53 AC-17", + "NIST SP 800-53 AC-19", + "NIST SP 800-53 AC-20", + "NIST SP 800-53 SC-15", + "AICPA TSC CC6.6", + "ISO 27001:2013 A.6.2.1", + "ISO 27001:2013 A.6.2.2", + "ISO 27001:2013 A.11.2.6", + "ISO 27001:2013 A.13.1.1", + "ISO 27001:2013 A.13.2.1", + ], + }, + "Workflow": {"Status": "NEW"}, + "RecordState": "ACTIVE", + } + yield finding diff --git a/eeauditor/check_register.py b/eeauditor/check_register.py new file mode 100644 index 00000000..31a42955 --- /dev/null +++ b/eeauditor/check_register.py @@ -0,0 +1,27 @@ +from functools import wraps + + +class CheckRegister(object): + checks = {} + + def register_check(self, cache_name="GLOBAL"): + """Decorator registers event handlers + + Args: + event_type: A string that matches the event type the wrapped function + will process. + """ + + def decorator_register(func): + if cache_name not in self.checks: + self.checks[cache_name] = {func.__name__: func} + else: + self.checks[cache_name].update({func.__name__: func}) + + @wraps(func) + def func_wrapper(*args, **kwargs): + return func(*args, **kwargs) + + return func_wrapper + + return decorator_register diff --git a/eeauditor/controller.py b/eeauditor/controller.py new file mode 100644 index 00000000..4c7a4e97 --- /dev/null +++ b/eeauditor/controller.py @@ -0,0 +1,154 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +from functools import partial +import getopt +import json +import os +import report +import sys +import boto3 +from pluginbase import PluginBase +from check_register import CheckRegister + + +sts = boto3.client("sts") + +here = os.path.abspath(os.path.dirname(__file__)) +get_path = partial(os.path.join, here) + + +class EEAuditor(object): + """ElectricEye controller + + Load and execute all auditor plugins. + """ + + def __init__(self, name): + self.name = name + self.plugin_base = PluginBase(package="electriceye") + # each check must be decorated with the @registry.register_check("cache_name") + # to be discovered during plugin loading. + self.registry = CheckRegister() + # vendor specific credentials dictionary + self.awsAccountId = sts.get_caller_identity()["Account"] + self.awsRegion = os.environ["AWS_REGION"] + # If there is a desire to add support for multiple clouds, this would be + # a great place to implement it. + self.source = self.plugin_base.make_plugin_source( + searchpath=[get_path("./auditors/aws")], identifier=self.name + ) + + def load_plugins(self, plugin_name): + if plugin_name: + try: + plugin = self.source.load_plugin(plugin_name) + plugin.setup(self) + except Exception as e: + print(f"Failed to load plugin {plugin_name} with exception {e}") + else: + for plugin_name in self.source.list_plugins(): + try: + plugin = self.source.load_plugin(plugin_name) + except Exception as e: + print(f"Failed to load plugin {plugin_name} with exception {e}") + + def run_checks(self, requested_check_name): + for cache_name, cache in self.registry.checks.items(): + # a dictionary to be used by checks that share a common cache + auditor_cache = {} + for check_name, check in cache.items(): + # if a specific check is requested, only run that one check + if ( + not requested_check_name + or requested_check_name + and requested_check_name == check_name + ): + try: + print(f"Executing check {self.name}.{check_name}") + for finding in check( + cache=auditor_cache, + awsAccountId=self.awsAccountId, + awsRegion=self.awsRegion, + ): + yield finding + except Exception as e: + print(f"Failed to execute check {check_name} with exception {e}") + + +def main(argv): + findings_list = [] # used if --output is specified + profile_name = "" + auditor_name = "" + check_name = "" + output = False + output_file = "" + help_text = ( + "auditor.py [-p -a -c -o ]" + ) + try: + opts, args = getopt.getopt( + argv, "ho:p:a:c:", ["help", "output=", "profile=", "auditor=", "check="] + ) + except getopt.GetoptError: + print(help_text) + sys.exit(2) + for opt, arg in opts: + if opt in ("-h", "--help"): + print(help_text) + sys.exit(2) + if opt in ("-o", "--output"): + output = True + output_file = arg + if opt in ("-p", "--profile"): + profile_name = arg.strip() + if opt in ("-a", "--auditor"): + auditor_name = arg + if opt in ("-c", "--check"): + check_name = arg + if profile_name: + boto3.setup_default_session(profile_name=profile_name) + + app = EEAuditor(name="AWS Auditor") + app.load_plugins(plugin_name=auditor_name) + first = True + file_location = "" + with open("findings.json", "w") as f: + print('{"Findings":[', file=f) + file_location = os.path.abspath(f.name) + for result in app.run_checks(requested_check_name=check_name): + # print a comma separation between findings except before first finding + if first: + first = False + else: + print(",", file=f) + json.dump(result, f, indent=2) + print("]}", file=f) + f.close() + securityhub = boto3.client("securityhub") + with open(file_location) as f: + findings = json.load(f) + securityhub.batch_import_findings(Findings=findings["Findings"]) + f.close() + if output: + report.csv_output(input_file=file_location, output_file=output_file) + print("Done") + + +if __name__ == "__main__": + # this is for local testing where the AWS_REGION is not liekly set + if not os.environ.get("AWS_REGION", None): + os.environ["AWS_REGION"] = "us-east-1" + main(sys.argv[1:]) diff --git a/eeauditor/report.py b/eeauditor/report.py new file mode 100644 index 00000000..cd67478e --- /dev/null +++ b/eeauditor/report.py @@ -0,0 +1,57 @@ +# This file is part of ElectricEye. + +# ElectricEye is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# ElectricEye is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License along with ElectricEye. +# If not, see https://github.com/jonrau1/ElectricEye/blob/master/LICENSE. + +import csv +import json +from functools import reduce + +# Return nested dictionary values by passing in dictionary and keys separated by "." +def deep_get(dictionary, keys): + return reduce( + lambda d, key: d.get(key) if isinstance(d, dict) else None, keys.split("."), dictionary, + ) + + +def csv_output(input_file, output_file): + csv_columns = [ + {"name": "Id", "path": "Id"}, + {"name": "Title", "path": "Title"}, + {"name": "ProductArn", "path": "ProductArn"}, + {"name": "AwsAccountId", "path": "AwsAccountId"}, + {"name": "Severity", "path": "Severity.Label"}, + {"name": "Confidence", "path": "Confidence"}, + {"name": "Description", "path": "Description"}, + {"name": "RecordState", "path": "RecordState"}, + {"name": "Compliance Status", "path": "Compliance.Status"}, + {"name": "Remediation Recommendation", "path": "Remediation.Recommendation.Text",}, + {"name": "Remediation Recommendation Link", "path": "Remediation.Recommendation.Url",}, + ] + csv_file = output_file + try: + with open(input_file) as f: + findings_file = json.load(f) + findings = findings_file["Findings"] + with open(csv_file, "w") as csvfile: + writer = csv.writer(csvfile, dialect="excel") + writer.writerow(item["name"] for item in csv_columns) + for finding in findings: + row_data = [] + for column_dict in csv_columns: + row_data.append(deep_get(finding, column_dict["path"])) + writer.writerow(row_data) + csvfile.close() + f.close() + except IOError: + print("I/O error") diff --git a/findings.json b/findings.json new file mode 100644 index 00000000..72b34d08 --- /dev/null +++ b/findings.json @@ -0,0 +1,2209 @@ +{"Findings":[ +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:cacheMe/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:cacheMe", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function cacheMe has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:cacheMe", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:workflow-callback/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:workflow-callback", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function workflow-callback has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:workflow-callback", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverlessrepo-task-monit-dynamodbprocessstreampyt-1V5E6UO6SLJXB", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:test_async/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:test_async", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function test_async has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:test_async", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:rules_engine/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:rules_engine", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function rules_engine has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:rules_engine", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:kinesis_event_writer/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:kinesis_event_writer", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function kinesis_event_writer has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:kinesis_event_writer", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-result_runner/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-result_runner", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function serverless-flask-dev-result_runner has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-result_runner", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:lambda-runner/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:lambda-runner", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function lambda-runner has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:lambda-runner", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-engine/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-engine", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function serverless-flask-dev-engine has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-engine", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:rock-paper-scissors/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:rock-paper-scissors", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function rock-paper-scissors has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:rock-paper-scissors", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:toSlack-dev-to_slack/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:toSlack-dev-to_slack", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function toSlack-dev-to_slack has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:toSlack-dev-to_slack", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-lambda_runner/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-lambda_runner", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function serverless-flask-dev-lambda_runner has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-lambda_runner", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:add/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:add", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "INFORMATIONAL" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function add has been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:add", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "RESOLVED" + }, + "RecordState": "ARCHIVED" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:task-writer/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:task-writer", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function task-writer has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:task-writer", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:reservedCurrency/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:reservedCurrency", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function reservedCurrency has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:reservedCurrency", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:high-low/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:high-low", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function high-low has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:high-low", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:stock-picker-dev-stock-picker/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:stock-picker-dev-stock-picker", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "INFORMATIONAL" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function stock-picker-dev-stock-picker has been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:stock-picker-dev-stock-picker", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "RESOLVED" + }, + "RecordState": "ARCHIVED" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:workflow-dev-app/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:workflow-dev-app", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function workflow-dev-app has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:workflow-dev-app", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:my-first-test/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:my-first-test", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "INFORMATIONAL" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function my-first-test has been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:my-first-test", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "RESOLVED" + }, + "RecordState": "ARCHIVED" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:reddit-slackbot-dev-runner/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:reddit-slackbot-dev-runner", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "INFORMATIONAL" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function reddit-slackbot-dev-runner has been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:reddit-slackbot-dev-runner", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "PASSED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "RESOLVED" + }, + "RecordState": "ARCHIVED" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-app/lambda-function-unused-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-app", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:05.837529+00:00", + "CreatedAt": "2020-06-15T20:24:05.837529+00:00", + "UpdatedAt": "2020-06-15T20:24:05.837529+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[Lambda.1] Lambda functions should be deleted after 30 days of no use", + "Description": "Lambda function serverless-flask-dev-app has not been used or updated in the last 30 days.", + "Remediation": { + "Recommendation": { + "Text": "For more information on best practices for lambda functions refer to the Best Practices for Working with AWS Lambda Functions section of the Amazon Lambda Developer Guide", + "Url": "https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html#function-configuration" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsLambda", + "Id": "arn:aws:lambda:us-east-1:057637124865:function:serverless-flask-dev-app", + "Partition": "aws", + "Region": "us-east-1" + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.AM-2", + "NIST SP 800-53 CM-8", + "NIST SP 800-53 PM-5", + "AICPA TSC CC3.2", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.1.1", + "ISO 27001:2013 A.8.1.2", + "ISO 27001:2013 A.12.5.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-metrics-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.274215+00:00", + "CreatedAt": "2020-06-15T20:24:09.274215+00:00", + "UpdatedAt": "2020-06-15T20:24:09.274215+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask does not have CloudWatch metrics enabled. You can monitor API execution by using CloudWatch, which collects and processes raw data from API Gateway into readable, near-real-time metrics. These statistics are recorded for a period of 15 months so you can access historical information and gain a better perspective on how your web application or service is performing. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-metrics-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.274215+00:00", + "CreatedAt": "2020-06-15T20:24:09.274215+00:00", + "UpdatedAt": "2020-06-15T20:24:09.274215+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", + "Description": "API Gateway stage default for Rest API workflow-callback-API does not have CloudWatch metrics enabled. You can monitor API execution by using CloudWatch, which collects and processes raw data from API Gateway into readable, near-real-time metrics. These statistics are recorded for a period of 15 months so you can access historical information and gain a better perspective on how your web application or service is performing. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-metrics-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.274215+00:00", + "CreatedAt": "2020-06-15T20:24:09.274215+00:00", + "UpdatedAt": "2020-06-15T20:24:09.274215+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.1] API Gateway Rest API Stages should have CloudWatch Metrics enabled", + "Description": "API Gateway stage dev for Rest API dev-workflow does not have CloudWatch metrics enabled. You can monitor API execution by using CloudWatch, which collects and processes raw data from API Gateway into readable, near-real-time metrics. These statistics are recorded for a period of 15 months so you can access historical information and gain a better perspective on how your web application or service is performing. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch Metrics enabled refer to the Monitor API Execution with Amazon CloudWatch section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/monitoring-cloudwatch.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-api-logging-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.758802+00:00", + "CreatedAt": "2020-06-15T20:24:09.758802+00:00", + "UpdatedAt": "2020-06-15T20:24:09.758802+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask does not have CloudWatch API Logging enabled. To help debug issues related to request execution or client access to your API, you can enable Amazon CloudWatch Logs to log API calls. The logged data includes errors or execution traces (such as request or response parameter values or payloads), data used by Lambda authorizers (formerly known as custom authorizers), whether API keys are required, whether usage plans are enabled, and so on. Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-api-logging-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.758802+00:00", + "CreatedAt": "2020-06-15T20:24:09.758802+00:00", + "UpdatedAt": "2020-06-15T20:24:09.758802+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", + "Description": "API Gateway stage default for Rest API workflow-callback-API does not have CloudWatch API Logging enabled. To help debug issues related to request execution or client access to your API, you can enable Amazon CloudWatch Logs to log API calls. The logged data includes errors or execution traces (such as request or response parameter values or payloads), data used by Lambda authorizers (formerly known as custom authorizers), whether API keys are required, whether usage plans are enabled, and so on. Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-api-logging-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:09.758802+00:00", + "CreatedAt": "2020-06-15T20:24:09.758802+00:00", + "UpdatedAt": "2020-06-15T20:24:09.758802+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.2] API Gateway Rest API Stages should have CloudWatch API Logging enabled", + "Description": "API Gateway stage dev for Rest API dev-workflow does not have CloudWatch API Logging enabled. To help debug issues related to request execution or client access to your API, you can enable Amazon CloudWatch Logs to log API calls. The logged data includes errors or execution traces (such as request or response parameter values or payloads), data used by Lambda authorizers (formerly known as custom authorizers), whether API keys are required, whether usage plans are enabled, and so on. Refer to the remediation instructions if this configuration is not intended.", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have CloudWatch API Logging enabled refer to the Set Up CloudWatch API Logging in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-logging.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-caching-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.025742+00:00", + "CreatedAt": "2020-06-15T20:24:10.025742+00:00", + "UpdatedAt": "2020-06-15T20:24:10.025742+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask does not have Caching enabled. You can enable API caching in Amazon API Gateway to cache your endpoints responses. With caching, you can reduce the number of calls made to your endpoint and also improve the latency of requests to your API. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-caching-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.025742+00:00", + "CreatedAt": "2020-06-15T20:24:10.025742+00:00", + "UpdatedAt": "2020-06-15T20:24:10.025742+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", + "Description": "API Gateway stage default for Rest API workflow-callback-API does not have Caching enabled. You can enable API caching in Amazon API Gateway to cache your endpoints responses. With caching, you can reduce the number of calls made to your endpoint and also improve the latency of requests to your API. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-caching-enabled-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.025742+00:00", + "CreatedAt": "2020-06-15T20:24:10.025742+00:00", + "UpdatedAt": "2020-06-15T20:24:10.025742+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.3] API Gateway Rest API Stages should have Caching enabled", + "Description": "API Gateway stage dev for Rest API dev-workflow does not have Caching enabled. You can enable API caching in Amazon API Gateway to cache your endpoints responses. With caching, you can reduce the number of calls made to your endpoint and also improve the latency of requests to your API. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching enabled refer to the Enable API Caching to Enhance Responsiveness section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF ID.BE-5", + "NIST CSF PR.PT-5", + "NIST SP 800-53 CP-2", + "NIST SP 800-53 CP-11", + "NIST SP 800-53 SA-13", + "NIST SP 800-53 SA14", + "AICPA TSC CC3.1", + "AICPA TSC A1.2", + "ISO 27001:2013 A.11.1.4", + "ISO 27001:2013 A.17.1.1", + "ISO 27001:2013 A.17.1.2", + "ISO 27001:2013 A.17.2.1" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-cache-encryption-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.287523+00:00", + "CreatedAt": "2020-06-15T20:24:10.287523+00:00", + "UpdatedAt": "2020-06-15T20:24:10.287523+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask does not have cache encryption enabled. If you choose to enable caching for a REST API, you can enable cache encryption. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-cache-encryption-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.287523+00:00", + "CreatedAt": "2020-06-15T20:24:10.287523+00:00", + "UpdatedAt": "2020-06-15T20:24:10.287523+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", + "Description": "API Gateway stage default for Rest API workflow-callback-API does not have cache encryption enabled. If you choose to enable caching for a REST API, you can enable cache encryption. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-cache-encryption-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.287523+00:00", + "CreatedAt": "2020-06-15T20:24:10.287523+00:00", + "UpdatedAt": "2020-06-15T20:24:10.287523+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.4] API Gateway Rest API Stages should have cache encryption enabled", + "Description": "API Gateway stage dev for Rest API dev-workflow does not have cache encryption enabled. If you choose to enable caching for a REST API, you can enable cache encryption. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have caching encryption enabled refer to the Override API Gateway Stage-Level Caching for Method Caching section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html#override-api-gateway-stage-cache-for-method-cache" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF PR.DS-1", + "NIST SP 800-53 MP-8", + "NIST SP 800-53 SC-12", + "NIST SP 800-53 SC-28", + "AICPA TSC CC6.1", + "ISO 27001:2013 A.8.2.3" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-xray-tracing-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.557861+00:00", + "CreatedAt": "2020-06-15T20:24:10.557861+00:00", + "UpdatedAt": "2020-06-15T20:24:10.557861+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask does not have tracing enabled. Because X-Ray gives you an end-to-end view of an entire request, you can analyze latencies in your APIs and their backend services. You can use an X-Ray service map to view the latency of an entire request and that of the downstream services that are integrated with X-Ray. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-xray-tracing-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.557861+00:00", + "CreatedAt": "2020-06-15T20:24:10.557861+00:00", + "UpdatedAt": "2020-06-15T20:24:10.557861+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", + "Description": "API Gateway stage default for Rest API workflow-callback-API does not have tracing enabled. Because X-Ray gives you an end-to-end view of an entire request, you can analyze latencies in your APIs and their backend services. You can use an X-Ray service map to view the latency of an entire request and that of the downstream services that are integrated with X-Ray. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-xray-tracing-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "FirstObservedAt": "2020-06-15T20:24:10.557861+00:00", + "CreatedAt": "2020-06-15T20:24:10.557861+00:00", + "UpdatedAt": "2020-06-15T20:24:10.557861+00:00", + "Severity": { + "Label": "LOW" + }, + "Confidence": 99, + "Title": "[APIGateway.5] API Gateway Rest API Stages should have tracing enabled", + "Description": "API Gateway stage dev for Rest API dev-workflow does not have tracing enabled. Because X-Ray gives you an end-to-end view of an entire request, you can analyze latencies in your APIs and their backend services. You can use an X-Ray service map to view the latency of an entire request and that of the downstream services that are integrated with X-Ray. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should have tracing enabled refer to the Set Up X-Ray Tracing in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-set-up-tracing.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-3", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 IR-5", + "NIST SP 800-53 IR-8", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.7" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev/apigateway-stage-waf-protection-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.803572+00:00", + "CreatedAt": "2020-06-15T20:24:10.803572+00:00", + "UpdatedAt": "2020-06-15T20:24:10.803572+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", + "Description": "API Gateway stage dev for Rest API dev-serverless-flask is not protected by an AWS WAF Web ACL. You can use AWS WAF to protect your API Gateway API from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect API availability and performance, compromise security, or consume excessive resources. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/5dq0gatjul/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "l6m7kr", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default/apigateway-stage-waf-protection-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.803572+00:00", + "CreatedAt": "2020-06-15T20:24:10.803572+00:00", + "UpdatedAt": "2020-06-15T20:24:10.803572+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", + "Description": "API Gateway stage default for Rest API workflow-callback-API is not protected by an AWS WAF Web ACL. You can use AWS WAF to protect your API Gateway API from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect API availability and performance, compromise security, or consume excessive resources. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9kb0qea893/stages/default", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "bv4iij", + "stageName": "default" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}, +{ + "SchemaVersion": "2018-10-08", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev/apigateway-stage-waf-protection-check", + "ProductArn": "arn:aws:securityhub:us-east-1:057637124865:product/057637124865/default", + "GeneratorId": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "AwsAccountId": "057637124865", + "Types": [ + "Software and Configuration Checks/AWS Security Best Practices", + "Effects/Data Exposure" + ], + "FirstObservedAt": "2020-06-15T20:24:10.803572+00:00", + "CreatedAt": "2020-06-15T20:24:10.803572+00:00", + "UpdatedAt": "2020-06-15T20:24:10.803572+00:00", + "Severity": { + "Label": "HIGH" + }, + "Confidence": 99, + "Title": "[APIGateway.6] API Gateway Rest API Stages should be protected by an AWS WAF Web ACL", + "Description": "API Gateway stage dev for Rest API dev-workflow is not protected by an AWS WAF Web ACL. You can use AWS WAF to protect your API Gateway API from common web exploits, such as SQL injection and cross-site scripting (XSS) attacks. These could affect API availability and performance, compromise security, or consume excessive resources. Refer to the remediation instructions if this configuration is not intended", + "Remediation": { + "Recommendation": { + "Text": "If your API Gateway stage should be protected by WAF refer to the Set Up AWS WAF in API Gateway section of the Amazon API Gateway Developer Guide", + "Url": "https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-setup-waf.html" + } + }, + "ProductFields": { + "Product Name": "ElectricEye" + }, + "Resources": [ + { + "Type": "AwsApiGatewayRestApi", + "Id": "arn:aws:apigateway:us-east-1::/restapis/9zcwbrpvza/stages/dev", + "Partition": "aws", + "Region": "us-east-1", + "Details": { + "Other": { + "deploymentId": "k8x827", + "stageName": "dev" + } + } + } + ], + "Compliance": { + "Status": "FAILED", + "RelatedRequirements": [ + "NIST CSF DE.AE-2", + "NIST SP 800-53 AU-6", + "NIST SP 800-53 CA-7", + "NIST SP 800-53 IR-4", + "NIST SP 800-53 SI-4", + "AICPA TSC CC7.2", + "ISO 27001:2013 A.12.4.1", + "ISO 27001:2013 A.16.1.1", + "ISO 27001:2013 A.16.1.4" + ] + }, + "Workflow": { + "Status": "NEW" + }, + "RecordState": "ACTIVE" +}]} From a84c67b62f5bd78a3e888b49d7e10726a52e50ac Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Mon, 15 Jun 2020 17:23:26 -0500 Subject: [PATCH 6/7] remove call to setup --- eeauditor/controller.py | 1 - 1 file changed, 1 deletion(-) diff --git a/eeauditor/controller.py b/eeauditor/controller.py index 4c7a4e97..dd334999 100644 --- a/eeauditor/controller.py +++ b/eeauditor/controller.py @@ -55,7 +55,6 @@ def load_plugins(self, plugin_name): if plugin_name: try: plugin = self.source.load_plugin(plugin_name) - plugin.setup(self) except Exception as e: print(f"Failed to load plugin {plugin_name} with exception {e}") else: From 95b924fa60ec92f759072fb3b47e4c7d8efc0161 Mon Sep 17 00:00:00 2001 From: Jody Brazil Date: Mon, 15 Jun 2020 18:08:42 -0500 Subject: [PATCH 7/7] updates to dockerfile --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index a16352bf..486d767d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,10 +12,11 @@ LABEL maintainer="https://github.com/jonrau1" \ description="Continuously monitor your AWS services for configurations that can lead to degradation of confidentiality, integrity or availability. All results will be sent to Security Hub for further aggregation and analysis." COPY requirements.txt /tmp/requirements.txt -COPY audit_controller.py . +# NOTE: this will copy current auditors to container along with the required controller files +COPY ./eeauditor/ ./ RUN pip3 install -r /tmp/requirements.txt CMD \ aws s3 cp s3://${SH_SCRIPTS_BUCKET}/ ./auditors --recursive && \ - python audit_controller.py \ No newline at end of file + python controller.py \ No newline at end of file