diff --git a/.gitignore b/.gitignore index 79669d2..bf00902 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Custom test.py +test.md crossAccounts.json output.zip __fork/*.json diff --git a/frameworks/CIS/map.json b/frameworks/CIS/map.json index c914794..43eaf1e 100644 --- a/frameworks/CIS/map.json +++ b/frameworks/CIS/map.json @@ -9,7 +9,7 @@ }, "mapping": { "CloudTrail.": { - "1": ["cloudtrail.HasOneMultiRegionTrail"], + "1": ["cloudtrail.NeedToEnableCloudTrail", "cloudtrail.HasOneMultiRegionTrail"], "2": ["cloudtrail.RequiresKmsKey"], "4": ["cloudtrail.LogFileValidationEnabled"], "5": ["cloudtrail.CloudWatchLogsLogGroupArn"], diff --git a/frameworks/FrameworkPageBuilder.py b/frameworks/FrameworkPageBuilder.py index 2f0b5d5..d34da39 100644 --- a/frameworks/FrameworkPageBuilder.py +++ b/frameworks/FrameworkPageBuilder.py @@ -6,6 +6,7 @@ from frameworks.WAFS.WAFS import WAFS from frameworks.MSR.MSR import MSR from frameworks.CIS.CIS import CIS +from frameworks.CIS.CIS import NIST class FrameworkPageBuilder(PageBuilder): COMPLIANCE_STATUS = ["Not available", "Compliant", "Need Attention"] diff --git a/frameworks/NIST/NIST.py b/frameworks/NIST/NIST.py new file mode 100644 index 0000000..c47fbf2 --- /dev/null +++ b/frameworks/NIST/NIST.py @@ -0,0 +1,9 @@ +import json + +import constants as _C +from frameworks.Framework import Framework + +class NIST(Framework): + def __init__(self, data): + super().__init__(data) + pass \ No newline at end of file diff --git a/frameworks/NIST/NISTPageBuilder.py b/frameworks/NIST/NISTPageBuilder.py new file mode 100644 index 0000000..4102900 --- /dev/null +++ b/frameworks/NIST/NISTPageBuilder.py @@ -0,0 +1,6 @@ +from frameworks.FrameworkPageBuilder import FrameworkPageBuilder + +class NISTPageBuilder(FrameworkPageBuilder): + def init(self): + super().__init__() + self.template = 'default' \ No newline at end of file diff --git a/frameworks/NIST/map.json b/frameworks/NIST/map.json new file mode 100644 index 0000000..fd9c3b6 --- /dev/null +++ b/frameworks/NIST/map.json @@ -0,0 +1,375 @@ +{ + "metadata": { + "originator": "NIST", + "shortname": "NIST AWS", + "fullname": "National Institute of Standards and Technology (NIST) SP 800-53 Rev. 5", + "description": "[Work In Progress] The NIST Special Publication 800-53 Revision 5 provides a catalog of security and privacy controls for federal information systems and organizations to protect organizational operations and assets, individuals, other organizations, and the Nation from a diverse set of threats including hostile cyber attacks, natural disasters, structural failures, and human errors.", + "_": "https://docs.aws.amazon.com/securityhub/latest/userguide/nist-standard.html", + "emptyCheckDefaultMsg": "Please refer to the NIST control section for further details. Kindly provide evidence or artifacts demonstrating compliance with the respective NIST control." + }, + "mapping": { + "Account.": { + "1": [], + "2": [] + }, + "ACM.": { + "1": [] + }, + "APIGateway.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "8": [], + "9": [] + }, + "Appsync.": { + "5": [] + }, + "Autoscaling.": { + "1": [], + "2": [], + "3": [], + "5": [], + "6": [], + "9": [] + }, + "Backup.": { + "1": [] + }, + "CloudFront.": { + "1": [], + "3": [], + "4": [], + "5": [], + "6": [], + "7": [], + "8": [], + "9": [], + "10": [], + "12": [] + }, + "CloudTrail.": { + "1": ["cloudtrail.HasOneMultiRegionTrail"], + "2": ["cloudtrail.RequiresKmsKey"], + "4": ["cloudtrail.LogFileValidationEnabled"], + "5": ["cloudtrail.CloudWatchLogsLogGroupArn"] + }, + "CloudWatch.": { + "15": [], + "16": [], + "17": [] + }, + "CodeBuild.": { + "1": [], + "2": [], + "3": [], + "4": [] + }, + "Config.": { + "1": [] + }, + "DMS.": { + "1": [], + "6": [], + "7": [], + "8": [], + "9": [] + }, + "DocumentDB.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [] + }, + "DynamoDB.": { + "1": [], + "2": [], + "3": [], + "4": [], + "6": [] + }, + "EC2.": { + "1": ["ec2.EBSSnapshotIsPublic"], + "2": ["ec2.SGDefaultDisallowTraffic"], + "3": ["ec2.EBSInUse", "ec2.EBSEncrypted"], + "4": ["ec2.EC2Active"], + "5": [""], + "6": [], + "7": ["ec2.EBSEncrypted"], + "8": ["ec2.ASGIMDSv2"], + "9": ["ec2.EC2InstancePublicIP"], + "10": [], + "12": ["ec2.EC2EIPNotInUse"], + "13": ["ec2.SGSensitivePortOpenToAll", "ec2.SGAllPortOpenToAll"], + "15": ["ec2.EC2SubnetAutoPublicIP"], + "16": [], + "17": [], + "18": [], + "19": [], + "20": [], + "21": [], + "23": [], + "24": [], + "25": [], + "28": [], + "51": [] + + }, + "ECR.": { + "1": [], + "2": [], + "3": [] + }, + "ECS.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "8": [], + "9": [], + "10": [], + "12": [] + }, + "EFS.": { + "1": [], + "2": [], + "3": [], + "4": [] + }, + "EKS.": { + "1": ["eks.eksEndpointPublicAccess"], + "2": ["eks.eksClusterVersionEol"], + "8": ["eks.eksClusterLogging"] + }, + "ElastiCache.": { + "1": [], + "2": [], + "3": [], + "4": ["elasticache.EncInTransitAndRest"], + "5": ["elasticache.EncInTransitAndRest"], + "6": [], + "7": [] + }, + "ElasticBeanstalk.": { + "1": [], + "2": [] + }, + "ELB.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "6": [], + "7": ["ec2.ELBConnectionDraining"], + "8": [], + "9": ["ec2.ELBCrossZone"], + "10": [], + "12": [], + "13": [], + "14": [], + "16": ["ec2.ELBEnableWAF"] + }, + "EMR.": { + "1": [], + "2": [] + }, + "ES.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "6": [], + "7": [], + "8": [] + }, + "EventBridge.": { + "3": [], + "4": [] + }, + "FSx.": { + "1": [] + }, + "GuardDuty.": { + "1": [] + }, + "IAM.": { + "1": ["iam.FullAdminAccess"], + "2": ["iam.userNotUsingGroup","iam.InlinePolicy"], + "3": ["iam.hasAccessKeyNoRotate90days"], + "4": ["iam.rootHasAccessKey"], + "5": ["iam.mfaActive"], + "6": [], + "7": ["iam.passwordPolicyWeak"], + "8": ["iam.consoleLastAccess90", "iam.consoleLastAccess365"], + "9": ["iam.rootMfaActive"], + "19": ["iam.mfaActive"], + "21": ["iam.ManagedPolicyFullAccessOneServ"] + }, + "Kinesis.": { + "1": [] + }, + "KMS.": { + "1": [], + "2": [], + "3": ["kms.KeyInPendingDeletion"], + "4": ["kms.KeyRotationEnabled"] + }, + "Lambda.": { + "1": ["lambda.lambdaPublicAccess"], + "2": ["lambda.lambdaRuntimeUpdate"], + "3": [], + "5": [] + }, + "Macie.": { + "1": ["s3.MacieToEnable"], + "2": [] + }, + "MSK.": { + "1": [], + "2": [] + }, + "MQ.": { + "5": [], + "6": [] + }, + "Neptune.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "6": [], + "7": [], + "8": [], + "9": [] + }, + "NetworkFirewall.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "6": [], + "9": [] + }, + "Opensearch.": { + "1": ["opensearch.EncyptionAtRest"], + "2": ["opensearch.DomainWithinVPC"], + "3": ["opensearch.NodeToNodeEncryption"], + "4": ["opensearch.ApplicationLogs"], + "5": ["opensearch.AuditLogs"], + "6": ["opensearch.DataNodes"], + "7": ["opensearch.FineGrainedAccessControl"], + "8": ["opensearch.TLSEnforced"], + "10": ["opensearch.ServiceSoftwareVersion"] + }, + "PCA.": { + "1": [] + }, + "RDS.": { + "1": ["rds.SnapshotRDSIsPublic"], + "2": ["rds.PubliclyAccessible"], + "3": ["rds.StorageEncrypted"], + "4": [], + "5": ["rds.MultiAZ"], + "6": ["rds.EnhancedMonitor"], + "7": ["rds.DeleteProtection"], + "8": ["rds.DeleteProtection"], + "9": [], + "10": [], + "11": ["rds.Backup"], + "12": [], + "13": ["rds.AutoMinorVersionUpgrade"], + "14": [], + "15": ["rds.MultiAZ"], + "16": [], + "17": [], + "18": [], + "19": [], + "20": [], + "21": [], + "22": [], + "23": [], + "24": ["rds.DefaultMasterAdmin"], + "25": ["rdsDefaultMasterAdmin"], + "26": [], + "27": ["rds.StorageEncrypted"], + "34": [], + "35": ["rds.AutoMinorVersionUpgrade"] + }, + "Redshift.": { + "1": [], + "2": [], + "3": [], + "4": [], + "6": [], + "7": [], + "8": [], + "9": [], + "10": [] + }, + "Route53.": { + "2": [] + }, + "S3.": { + "1": ["s3.S3AccountPublicAccessBlock"], + "2": ["s3.PublicAccessBlock"], + "3": ["s3.PublicAccessBlock"], + "5": ["s3.TlsEnforced"], + "7": ["s3.CrossRegionReplication"], + "8": ["s3.PublicAccessBlock"], + "9": ["s3.BucketLogging"], + "10": ["s3.BucketVersioning", "s3.BucketLifecycle"], + "11": ["s3.EventNotification"], + "12": ["s3.AccessControlList"], + "13": ["s3.BucketLifecycle"], + "14": ["s3.BucketVersioning"], + "15": ["s3.ObjectLock"], + "17": ["ServerSideEncrypted", "s3.SSEWithKMS"], + "19": [], + "20": ["s3.MFADelete"] + }, + "Sagemaker.": { + "1": [], + "2": [], + "3": [] + }, + "SecretsManager.": { + "1": [], + "2": [], + "3": [], + "4": [] + }, + "SNS.": { + "1": [] + }, + "SQS.": { + "1": [] + }, + "SSM.": { + "1": [], + "2": [], + "3": [], + "4": [] + }, + "WAF.": { + "1": [], + "2": [], + "3": [], + "4": [], + "5": [], + "6": [], + "7": [], + "8": [], + "10": [], + "11": [], + "12": [] + } + } +} \ No newline at end of file diff --git a/frameworks/NIST/readme.md b/frameworks/NIST/readme.md new file mode 100644 index 0000000..43f6201 --- /dev/null +++ b/frameworks/NIST/readme.md @@ -0,0 +1 @@ +### This framework is a work in progress should be used as a reference only. There are currently many outstanding checks that are yet to be implemented. Please see [CONTRIBUTING](./CONTRIBUTING.md) if you would like to contribute to building this framework. \ No newline at end of file diff --git a/services/iam/iam.reporter.json b/services/iam/iam.reporter.json index c0ffc8d..34f98f9 100644 --- a/services/iam/iam.reporter.json +++ b/services/iam/iam.reporter.json @@ -104,6 +104,19 @@ "[IAM Password Policy]" ] }, + "passwordPolicyWeak": { + "category": "S", + "^description": "Your current password policy is not strong. Improving the strength of your password policy would improve the security of your account. Consider implementing best practices when setting the password policy. If you already configure as per your organization ", + "shortDesc": "Set a stronger password policy", + "criticality": "M", + "downtime": 0, + "slowness": 0, + "additionalCost": 0, + "needFullTest": 0, + "ref": [ + "[AWS Docs]" + ] + }, "passwordPolicyReuse": { "category": "S", "^description": "Your current password policy is not strong. Improving the strength of your password policy would improve the security of your account. Consider implementing best practices when setting the password policy. If you already configure as per your organization ", diff --git a/services/kms/kms.reporter.json b/services/kms/kms.reporter.json index b338ea4..5532305 100644 --- a/services/kms/kms.reporter.json +++ b/services/kms/kms.reporter.json @@ -27,13 +27,13 @@ }, "KeyInPendingDeletion":{ "category": "O", - "^description": "[Informational], no action needed. {$COUNT} KMS key is under Pending Deletion Stage.", + "^description": "[Warning] {$COUNT} KMS key is under Pending Deletion Stage. KMS keys cannot be recovered once deleted. Data encrypted under a KMS key is also permanently unrecoverable if the KMS key is deleted. If meaningful data has been encrypted under a KMS key scheduled for deletion, consider decrypting the data or re-encrypting the data under a new KMS key unless you are intentionally performing a cryptographic erasure.", "downtime": 0, "slowness": 0, "additionalCost": 0, "needFullTest": 0, "criticality": "I", - "shortDesc": "[Info] No Action Needed", + "shortDesc": "[Warning] Ensure intentional deletion", "ref": [ "[KMS Key State Explanation]" ] diff --git a/services/opensearch/drivers/OpensearchCommon.py b/services/opensearch/drivers/OpensearchCommon.py index 22eb0fb..8a81a44 100644 --- a/services/opensearch/drivers/OpensearchCommon.py +++ b/services/opensearch/drivers/OpensearchCommon.py @@ -74,7 +74,24 @@ def _checkMasterNodes(self): self.results["DedicatedMasterNodes"] = [-1, "Wrong number of dedicated master nodes"] return self.results["DedicatedMasterNodes"] = [1, "Sufficient dedicated master nodes"] - + + def _checkDataNodes(self): + total_nodes = self.cluster_config['InstanceCount'] + master_enabled = self.cluster_config["DedicatedMasterEnabled"] + master_nodes = 0 + if master_enabled: + master_nodes = self.cluster_config['DedicatedMasterCount'] + warm_enabled = self.cluster_config["WarmEnabled"] + warm_nodes = 0 + if warm_enabled: + warm_nodes = self.cluster_config['WarmCount'] + data_nodes = total_nodes - master_nodes - warm_nodes + + if data_nodes < 3: + self.results["DataNodes"] = [-1, "Insufficient data nodes"] + return + self.results["DataNodes"] = [1, "Sufficient data nodes"] + def _checkAvailabilityZones(self): enabled = self.cluster_config["ZoneAwarenessEnabled"] self.results["AvailabilityZones"] = [-1, "Multi-AZ not enabled"] @@ -147,6 +164,13 @@ def _checkNodeToNodeEncryption(self): if 'Enabled' in self.attribute['DomainStatus']['NodeToNodeEncryptionOptions']: self.results["NodeToNodeEncryption"] = [1, "Enabled"] + def _checkTLSEnforced(self): + self.results["TLSEnforced"] = [-1, "Disabled"] + if 'DomainStatus' in self.attribute: + if 'DomainEndpointOptions' in self.attribute['DomainStatus']: + if 'EnforceHTTPS' in self.attribute['DomainStatus']['DomainEndpointOptions']: + self.results["TLSEnforced"] = [1, "Enabled"] + def _checkSearchSlowLogs(self): self.results["SearchSlowLogs"] = [-1, "Disabled"] if 'DomainStatus' in self.attribute: @@ -154,6 +178,20 @@ def _checkSearchSlowLogs(self): if 'SEARCH_SLOW_LOGS' in self.attribute['DomainStatus']['LogPublishingOptions']: self.results["SearchSlowLogs"] = [1, "Enabled"] + def _checkApplicationLogs(self): + self.results["ApplicationLogs"] = [-1, "Disabled"] + if 'DomainStatus' in self.attribute: + if 'LogPublishingOptions' in self.attribute['DomainStatus']: + if 'ES_APPLICATION_LOGS' in self.attribute['DomainStatus']['LogPublishingOptions']: + self.results["SearchSlowLogs"] = [1, "Enabled"] + + def _checkAuditLogs(self): + self.results["AuditLogs"] = [-1, "Disabled"] + if 'DomainStatus' in self.attribute: + if 'LogPublishingOptions' in self.attribute['DomainStatus']: + if 'SEARCH_SLOW_LOGS' in self.attribute['DomainStatus']['LogPublishingOptions']: + self.results["AUDIT_LOGS"] = [1, "Enabled"] + def _checkAutoTune(self): self.results["AutoTune"] = [-1, "Disabled"] if 'DomainStatus' in self.attribute: diff --git a/services/opensearch/opensearch.reporter.json b/services/opensearch/opensearch.reporter.json index edf1b30..1ee3877 100644 --- a/services/opensearch/opensearch.reporter.json +++ b/services/opensearch/opensearch.reporter.json @@ -38,6 +38,19 @@ "Dedicated master nodes in Amazon OpenSearch Service]" ] }, + "DataNodes": { + "category": "R", + "^description": "An OpenSearch domain requires at least three data nodes for high availability and fault-tolerance. Deploying an OpenSearch domain with at least three data nodes ensures cluster operations if a node fails.", + "downtime": 0, + "slowness": 1, + "additionalCost": 1, + "criticality": "H", + "needFullTest": 0, + "shortDesc": "We recommend that you add three data nodes to each production OpenSearch Service domain.", + "ref": [ + "Data nodes in Amazon OpenSearch Service]" + ] + }, "AvailabilityZones": { "category": "R", "^description": "To prevent data loss and minimize cluster downtime in the event of a service disruption, you can distribute nodes across two or three Availability Zones in the same AWS Region. Availability Zones are isolated locations within each Region. With a two-AZ configuration, losing one Availability Zone means that you lose half of all domain capacity. Moving to three Availability Zones further reduces the impact of losing a single Availability Zone. Deploy mission-critical domains across three Availability Zones and two replica shards per index. This configuration lets OpenSearch Service distribute replica shards to different AZs than their corresponding primary shards. There are no cross-AZ data transfer charges for cluster communications between Availability Zones.", @@ -181,6 +194,19 @@ "[Enable node-to-node encryption]" ] }, + "TLSEnforced": { + "category": "S", + "^description": "HTTPS (TLS) can be used to help prevent potential attackers from using person-in-the-middle or similar attacks to eavesdrop on or manipulate network traffic. Only encrypted connections over HTTPS (TLS) should be allowed. Encrypting data in transit can affect performance. You should test your application with this feature to understand the performance profile and the impact of TLS. TLS 1.2 provides several security enhancements over previous versions of TLS. ", + "downtime": -1, + "slowness": -1, + "additionalCost": 0, + "criticality": "I", + "needFullTest": 0, + "shortDesc": "If your domain stores sensitive data, make sure the domain endpoint is configured to use the latest TLS security policy.", + "ref": [ + "[Enable node-to-node encryption]" + ] + }, "SearchSlowLogs": { "category": "P", "^description": "OpenSearch Service exposes OpenSearch error logs, search slow logs, indexing slow logs, and audit logs in Amazon CloudWatch Logs. Search slow logs, indexing slow logs, and error logs are useful for troubleshooting performance and stability issues. Audit logs, which are only available if you enable fine-grained access control to track user activity. For more information, see Logs in the OpenSearch documentation. Search slow logs and indexing slow logs are an important tool for understanding and troubleshooting the performance of your search and indexing operations. Enable search and index slow log delivery for all production domains. You must also configure logging thresholds—otherwise, CloudWatch won't capture the logs.", @@ -194,6 +220,32 @@ "[Enable log publishing]" ] }, + "ApplicationLogs": { + "category": "P", + "^description": "OpenSearch Service exposes OpenSearch error logs, search slow logs, indexing slow logs, and audit logs in Amazon CloudWatch Logs. Search slow logs, indexing slow logs, and error logs are useful for troubleshooting performance and stability issues. Audit logs, which are only available if you enable fine-grained access control to track user activity. For more information, see Logs in the OpenSearch documentation. Search slow logs and indexing slow logs are an important tool for understanding and troubleshooting the performance of your search and indexing operations. Enable search and index slow log delivery for all production domains. You must also configure logging thresholds—otherwise, CloudWatch won't capture the logs.", + "downtime": 0, + "slowness": 1, + "additionalCost": 1, + "criticality": "M", + "needFullTest": 0, + "shortDesc": " Enable error log delivery for all production domains.", + "ref": [ + "[Enable log publishing]" + ] + }, + "AuditLogs": { + "category": "P", + "^description": "OpenSearch Service exposes OpenSearch error logs, search slow logs, indexing slow logs, and audit logs in Amazon CloudWatch Logs. Search slow logs, indexing slow logs, and error logs are useful for troubleshooting performance and stability issues. Audit logs, which are only available if you enable fine-grained access control to track user activity. For more information, see Logs in the OpenSearch documentation. Search slow logs and indexing slow logs are an important tool for understanding and troubleshooting the performance of your search and indexing operations. Enable search and index slow log delivery for all production domains. You must also configure logging thresholds—otherwise, CloudWatch won't capture the logs.", + "downtime": 0, + "slowness": 1, + "additionalCost": 1, + "criticality": "M", + "needFullTest": 0, + "shortDesc": " Enable audit log delivery for all production domains.", + "ref": [ + "[Enable log publishing]" + ] + }, "AutoTune": { "category": "P", "^description": "Auto-Tune uses performance and usage metrics from your OpenSearch cluster to suggest changes to queue sizes, cache sizes, and Java virtual machine (JVM) settings on your nodes. These optional changes improve cluster speed and stability. You can revert to the default OpenSearch Service settings at any time. Auto-Tune is enabled by default on new domains unless you explicitly disable it.", diff --git a/services/s3/drivers/S3Bucket.py b/services/s3/drivers/S3Bucket.py index 6d2abf8..f2eba57 100644 --- a/services/s3/drivers/S3Bucket.py +++ b/services/s3/drivers/S3Bucket.py @@ -23,6 +23,8 @@ def _checkEncrypted(self): resp = self.s3Client.get_bucket_encryption( Bucket=self.bucket ) + if "kms" not in resp.get('ServerSideEncryptionConfiguration').get('Rules')[0].get('ApplyServerSideEncryptionByDefault').get('SSEAlgorithm'): + self.results['SSEWithKMS'] = [1, 'On'] except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'ServerSideEncryptionConfigurationNotFoundError': self.results['ServerSideEncrypted'] = [-1, 'Off'] @@ -70,14 +72,22 @@ def _checkObjectLock(self): self.results['ObjectLock'] = [-1, 'Off'] def _checkBucketReplication(self): - self.results['BucketReplication'] = [1, 'On'] try: + self.results['BucketReplication'] = [1, 'On'] + resp = self.s3Client.get_bucket_replication( Bucket=self.bucket ) + source_loc = self.s3Client.get_bucket_location( + Bucket=self.bucket + ) + target_loc = resp.get('ReplicationConfiguration').get('Rules')[0].get('Destination').get('Bucket') + if source_loc.get('LocationConstraint') != target_loc.split('.')[1]: + self.results['CrossRegionReplication'] = [1, 'On'] except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'ReplicationConfigurationNotFoundError': self.results['BucketReplication'] = [-1, 'Off'] + def _checkLifecycle(self): self.results['BucketLifecycle'] = [1, 'On'] @@ -101,6 +111,27 @@ def _checkLogging(self): except botocore.exceptions.ClientError as e: print("[{}] Unable to get Logging Informaton, skip".format(self.bucket)) + def _checkEventNotif(self): + self.results['EventNotification'] = [1, 'On'] + try: + resp = self.s3Client.get_bucket_notification_configuration( + Bucket=self.bucket + ) + self.results['EventNotification'] = [-1, 'On'] + except botocore.exceptions.ClientError as e: + if e.response['Error']['Code'] == 'NoSuchNotificationConfiguration': + self.results['EventNotification'] = [-1, 'Off'] + + def _checkACL(self): + try: + resp = self.s3Client.get_bucket_acl( + Bucket=self.bucket + ) + self.results['AccessControlList'] = [-1, 'Enabled'] + except botocore.exceptions.ClientError as e: + if e.response['Error']['Code'] == 'NoSuchAcl': + self.results['AccessControlList'] = [1, 'Disabled'] + def _checkIntelligentTiering(self): try: self.results['ObjectsInIntelligentTier'] = [1,'On'] diff --git a/services/s3/s3.reporter.json b/services/s3/s3.reporter.json index 07305b1..adceef6 100644 --- a/services/s3/s3.reporter.json +++ b/services/s3/s3.reporter.json @@ -3,7 +3,7 @@ "category": "S", "^description": "You have not enabled server side encryption (SSE) on {$COUNT} buckets which automatically encrypts objects uploaded to the bucket. If this bucket contains non-publically-available data, and you are not implementing client-side encryption, please enable SSE.", "shortDesc": "Enable SSE", - "criticality": "L", + "criticality": "M", "downtime": 0, "slowness": 0, "additionalCost": 0, @@ -12,6 +12,32 @@ "[Protecting data with encryption]" ] }, + "SSEWithKMS": { + "category": "S", + "^description": "You have not enabled server side encryption (SSE) with KMS on {$COUNT} buckets which automatically encrypts objects uploaded to the bucket. If this bucket contains non-publically-available data, and you are not implementing client-side encryption, please enable SSE with KMS.", + "shortDesc": "Enable SSE with KMS", + "criticality": "M", + "downtime": 0, + "slowness": 0, + "additionalCost": 0, + "needFullTest": 0, + "ref": [ + "[Protecting data with encryption]" + ] + }, + "AccessControlList": { + "category": "S", + "^description": "You are using {$COUNT} S3 buckets with ACLs. ACLs are legacy access control mechanisms that predate IAM. Instead of ACLs, we recommend using S3 bucket policies or AWS Identity and Access Management (IAM) policies to manage access to your S3 buckets.", + "shortDesc": "Enable SSE", + "criticality": "L", + "downtime": 0, + "slowness": 0, + "additionalCost": 0, + "needFullTest": 0, + "ref": [ + "[Protecting data with IAM]" + ] + }, "PublicAccessBlock": { "category": "S", "^description": "You have disabled public access block on {$COUNT} S3 buckets.This leaves your data to be accessible by anyone. Unless absolutely necessary, enable public access block. Block Public Access at the S3 bucket level provides controls to ensure that objects never have public access. Public access is granted to buckets and objects through access control lists (ACLs), bucket policies, or both.", @@ -79,6 +105,32 @@ "[AWS Docs]" ] }, + "CrossRegionReplication": { + "category": "RS", + "^description": "You have not enabled cross-region replication on {$COUNT} buckets. Replication enables automatic, asynchronous copying of objects across Amazon S3 buckets.", + "shortDesc": "Enable Bucket Replication", + "criticality": "I", + "downtime": 0, + "slowness": 0, + "additionalCost": 1, + "needFullTest": 0, + "ref": [ + "[AWS Docs]" + ] + }, + "EventNotification": { + "category": "OS", + "^description": "When you enable S3 Event Notifications, you receive alerts when specific events occur that impact your S3 buckets. For example, you can be notified of object creation, object removal, and object restoration. These notifications can alert relevant teams to accidental or intentional modifications that may lead to unauthorized data access.", + "shortDesc": "Enable Event Notification", + "criticality": "I", + "downtime": 0, + "slowness": 0, + "additionalCost": 1, + "needFullTest": 0, + "ref": [ + "[AWS Docs]" + ] + }, "BucketLifecycle": { "category": "CO", "^description": "You have not configured lifecycle policies for objects in {$COUNT} buckets. Lifecycle configuration is a set of rules that define actions that Amazon S3 applies to a group of objects. This will save you cost by moving infrequently accessed objects to lower cost storage tiers and expiring objects that are no longer needed.",