sraverify 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sraverify/__init__.py +36 -0
- sraverify/checks/__init__.py +56 -0
- sraverify/checks/accessanalyzer/SRA_IAA_1.py +188 -0
- sraverify/checks/accessanalyzer/SRA_IAA_2.py +162 -0
- sraverify/checks/accessanalyzer/SRA_IAA_3.py +260 -0
- sraverify/checks/accessanalyzer/SRA_IAA_4.py +207 -0
- sraverify/checks/accessanalyzer/__init__.py +3 -0
- sraverify/checks/cloudtrail/SRA-CT-1.py +220 -0
- sraverify/checks/cloudtrail/SRA-CT-10.py +229 -0
- sraverify/checks/cloudtrail/SRA-CT-11.py +242 -0
- sraverify/checks/cloudtrail/SRA-CT-12.py +163 -0
- sraverify/checks/cloudtrail/SRA-CT-13.py +279 -0
- sraverify/checks/cloudtrail/SRA-CT-2.py +218 -0
- sraverify/checks/cloudtrail/SRA-CT-3.py +196 -0
- sraverify/checks/cloudtrail/SRA-CT-4.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-5.py +200 -0
- sraverify/checks/cloudtrail/SRA-CT-6.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-7.py +194 -0
- sraverify/checks/cloudtrail/SRA-CT-8.py +226 -0
- sraverify/checks/cloudtrail/SRA-CT-9.py +226 -0
- sraverify/checks/cloudtrail/__init__.py +3 -0
- sraverify/checks/config/SRA-CONFIG-1.py +197 -0
- sraverify/checks/config/__init__.py +3 -0
- sraverify/core/__init__.py +3 -0
- sraverify/core/check.py +227 -0
- sraverify/core/logging.py +37 -0
- sraverify/core/session.py +47 -0
- sraverify/lib/__init__.py +4 -0
- sraverify/lib/audit_info.py +37 -0
- sraverify/lib/banner.py +42 -0
- sraverify/lib/check_loader.py +80 -0
- sraverify/lib/org_mgmt_checker.py +86 -0
- sraverify/lib/outputs.py +46 -0
- sraverify/lib/progress.py +75 -0
- sraverify/lib/regions.py +27 -0
- sraverify/lib/session.py +23 -0
- sraverify/main.py +350 -0
- sraverify/services/__init__.py +3 -0
- sraverify/services/accessanalyzer/__init__.py +15 -0
- sraverify/services/accessanalyzer/base.py +123 -0
- sraverify/services/accessanalyzer/checks/__init__.py +3 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_01.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_02.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_03.py +103 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_04.py +139 -0
- sraverify/services/accessanalyzer/client.py +123 -0
- sraverify/services/account/__init__.py +9 -0
- sraverify/services/account/base.py +56 -0
- sraverify/services/account/checks/__init__.py +1 -0
- sraverify/services/account/checks/sra_account_01.py +65 -0
- sraverify/services/account/checks/sra_account_02.py +63 -0
- sraverify/services/account/checks/sra_account_03.py +63 -0
- sraverify/services/account/client.py +51 -0
- sraverify/services/auditmanager/__init__.py +10 -0
- sraverify/services/auditmanager/base.py +72 -0
- sraverify/services/auditmanager/checks/__init__.py +1 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_01.py +58 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_02.py +80 -0
- sraverify/services/auditmanager/client.py +58 -0
- sraverify/services/cloudtrail/__init__.py +33 -0
- sraverify/services/cloudtrail/base.py +167 -0
- sraverify/services/cloudtrail/checks/__init__.py +1 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_01.py +83 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_02.py +99 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_03.py +94 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_04.py +92 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_05.py +106 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_06.py +93 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_07.py +96 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_08.py +145 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_09.py +167 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_10.py +162 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_11.py +178 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_12.py +77 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_13.py +120 -0
- sraverify/services/cloudtrail/client.py +118 -0
- sraverify/services/config/__init__.py +25 -0
- sraverify/services/config/base.py +249 -0
- sraverify/services/config/checks/__init__.py +1 -0
- sraverify/services/config/checks/sra_config_01.py +123 -0
- sraverify/services/config/checks/sra_config_02.py +156 -0
- sraverify/services/config/checks/sra_config_03.py +149 -0
- sraverify/services/config/checks/sra_config_04.py +104 -0
- sraverify/services/config/checks/sra_config_05.py +104 -0
- sraverify/services/config/checks/sra_config_06.py +194 -0
- sraverify/services/config/checks/sra_config_07.py +162 -0
- sraverify/services/config/checks/sra_config_08.py +185 -0
- sraverify/services/config/checks/sra_config_09.py +177 -0
- sraverify/services/config/client.py +264 -0
- sraverify/services/ec2/__init__.py +8 -0
- sraverify/services/ec2/base.py +75 -0
- sraverify/services/ec2/checks/__init__.py +1 -0
- sraverify/services/ec2/checks/sra_ec2_01.py +83 -0
- sraverify/services/ec2/client.py +63 -0
- sraverify/services/firewallmanager/__init__.py +23 -0
- sraverify/services/firewallmanager/base.py +48 -0
- sraverify/services/firewallmanager/checks/__init__.py +1 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_01.py +75 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_02.py +57 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_03.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_04.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_05.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_06.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_07.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_08.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_09.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_10.py +71 -0
- sraverify/services/firewallmanager/client.py +40 -0
- sraverify/services/guardduty/__init__.py +58 -0
- sraverify/services/guardduty/base.py +207 -0
- sraverify/services/guardduty/checks/__init__.py +3 -0
- sraverify/services/guardduty/checks/sra_guardduty_01.py +51 -0
- sraverify/services/guardduty/checks/sra_guardduty_02.py +80 -0
- sraverify/services/guardduty/checks/sra_guardduty_03.py +77 -0
- sraverify/services/guardduty/checks/sra_guardduty_04.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_05.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_06.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_07.py +85 -0
- sraverify/services/guardduty/checks/sra_guardduty_08.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_09.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_10.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_11.py +93 -0
- sraverify/services/guardduty/checks/sra_guardduty_12.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_13.py +90 -0
- sraverify/services/guardduty/checks/sra_guardduty_14.py +136 -0
- sraverify/services/guardduty/checks/sra_guardduty_15.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_16.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_17.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_18.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_19.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_20.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_21.py +112 -0
- sraverify/services/guardduty/checks/sra_guardduty_22.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_23.py +154 -0
- sraverify/services/guardduty/checks/sra_guardduty_24.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_25.py +111 -0
- sraverify/services/guardduty/client.py +107 -0
- sraverify/services/inspector/__init__.py +29 -0
- sraverify/services/inspector/base.py +233 -0
- sraverify/services/inspector/checks/__init__.py +3 -0
- sraverify/services/inspector/checks/sra_inspector_01.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_02.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_03.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_04.py +70 -0
- sraverify/services/inspector/checks/sra_inspector_05.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_06.py +115 -0
- sraverify/services/inspector/checks/sra_inspector_07.py +109 -0
- sraverify/services/inspector/checks/sra_inspector_08.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_09.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_10.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_11.py +69 -0
- sraverify/services/inspector/client.py +99 -0
- sraverify/services/macie/__init__.py +27 -0
- sraverify/services/macie/base.py +271 -0
- sraverify/services/macie/checks/__init__.py +1 -0
- sraverify/services/macie/checks/sra_macie_01.py +100 -0
- sraverify/services/macie/checks/sra_macie_02.py +102 -0
- sraverify/services/macie/checks/sra_macie_03.py +152 -0
- sraverify/services/macie/checks/sra_macie_04.py +120 -0
- sraverify/services/macie/checks/sra_macie_05.py +85 -0
- sraverify/services/macie/checks/sra_macie_06.py +124 -0
- sraverify/services/macie/checks/sra_macie_07.py +138 -0
- sraverify/services/macie/checks/sra_macie_08.py +82 -0
- sraverify/services/macie/checks/sra_macie_09.py +103 -0
- sraverify/services/macie/checks/sra_macie_10.py +81 -0
- sraverify/services/macie/client.py +220 -0
- sraverify/services/s3/__init__.py +16 -0
- sraverify/services/s3/base.py +69 -0
- sraverify/services/s3/checks/__init__.py +1 -0
- sraverify/services/s3/checks/sra_s3_01.py +89 -0
- sraverify/services/s3/checks/sra_s3_02.py +89 -0
- sraverify/services/s3/checks/sra_s3_03.py +88 -0
- sraverify/services/s3/checks/sra_s3_04.py +88 -0
- sraverify/services/s3/client.py +52 -0
- sraverify/services/securityhub/__init__.py +27 -0
- sraverify/services/securityhub/base.py +349 -0
- sraverify/services/securityhub/checks/__init__.py +1 -0
- sraverify/services/securityhub/checks/sra_securityhub_01.py +115 -0
- sraverify/services/securityhub/checks/sra_securityhub_02.py +114 -0
- sraverify/services/securityhub/checks/sra_securityhub_03.py +136 -0
- sraverify/services/securityhub/checks/sra_securityhub_04.py +75 -0
- sraverify/services/securityhub/checks/sra_securityhub_05.py +102 -0
- sraverify/services/securityhub/checks/sra_securityhub_06.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_07.py +121 -0
- sraverify/services/securityhub/checks/sra_securityhub_08.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_09.py +100 -0
- sraverify/services/securityhub/checks/sra_securityhub_10.py +94 -0
- sraverify/services/securityhub/checks/sra_securityhub_11.py +73 -0
- sraverify/services/securityhub/client.py +249 -0
- sraverify/services/securityincidentresponse/__init__.py +13 -0
- sraverify/services/securityincidentresponse/base.py +95 -0
- sraverify/services/securityincidentresponse/checks/__init__.py +1 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_01.py +77 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_02.py +72 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_03.py +86 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_04.py +117 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_05.py +55 -0
- sraverify/services/securityincidentresponse/client.py +71 -0
- sraverify/services/securitylake/__init__.py +39 -0
- sraverify/services/securitylake/base.py +461 -0
- sraverify/services/securitylake/checks/__init__.py +1 -0
- sraverify/services/securitylake/checks/sra_securitylake_01.py +98 -0
- sraverify/services/securitylake/checks/sra_securitylake_02.py +133 -0
- sraverify/services/securitylake/checks/sra_securitylake_03.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_04.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_05.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_06.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_07.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_08.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_09.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_10.py +106 -0
- sraverify/services/securitylake/checks/sra_securitylake_11.py +109 -0
- sraverify/services/securitylake/checks/sra_securitylake_12.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_13.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_14.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_15.py +120 -0
- sraverify/services/securitylake/checks/sra_securitylake_16.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_17.py +103 -0
- sraverify/services/securitylake/client.py +247 -0
- sraverify/services/shield/__init__.py +33 -0
- sraverify/services/shield/base.py +199 -0
- sraverify/services/shield/checks/__init__.py +1 -0
- sraverify/services/shield/checks/sra_shield_01.py +68 -0
- sraverify/services/shield/checks/sra_shield_02.py +77 -0
- sraverify/services/shield/checks/sra_shield_03.py +84 -0
- sraverify/services/shield/checks/sra_shield_04.py +84 -0
- sraverify/services/shield/checks/sra_shield_05.py +84 -0
- sraverify/services/shield/checks/sra_shield_06.py +84 -0
- sraverify/services/shield/checks/sra_shield_07.py +84 -0
- sraverify/services/shield/checks/sra_shield_08.py +69 -0
- sraverify/services/shield/checks/sra_shield_09.py +86 -0
- sraverify/services/shield/checks/sra_shield_10.py +100 -0
- sraverify/services/shield/checks/sra_shield_11.py +71 -0
- sraverify/services/shield/checks/sra_shield_12.py +130 -0
- sraverify/services/shield/checks/sra_shield_13.py +112 -0
- sraverify/services/shield/checks/sra_shield_14.py +111 -0
- sraverify/services/shield/client.py +214 -0
- sraverify/services/waf/__init__.py +21 -0
- sraverify/services/waf/base.py +100 -0
- sraverify/services/waf/checks/__init__.py +1 -0
- sraverify/services/waf/checks/sra_waf_01.py +63 -0
- sraverify/services/waf/checks/sra_waf_02.py +82 -0
- sraverify/services/waf/checks/sra_waf_03.py +123 -0
- sraverify/services/waf/checks/sra_waf_04.py +94 -0
- sraverify/services/waf/checks/sra_waf_05.py +94 -0
- sraverify/services/waf/checks/sra_waf_06.py +91 -0
- sraverify/services/waf/checks/sra_waf_07.py +94 -0
- sraverify/services/waf/checks/sra_waf_08.py +66 -0
- sraverify/services/waf/checks/sra_waf_09.py +95 -0
- sraverify/services/waf/client.py +109 -0
- sraverify/utils/__init__.py +3 -0
- sraverify/utils/banner.py +65 -0
- sraverify/utils/outputs.py +57 -0
- sraverify/utils/progress.py +97 -0
- sraverify-0.1.0.dist-info/LICENSE +175 -0
- sraverify-0.1.0.dist-info/METADATA +516 -0
- sraverify-0.1.0.dist-info/NOTICE +1 -0
- sraverify-0.1.0.dist-info/RECORD +261 -0
- sraverify-0.1.0.dist-info/WHEEL +5 -0
- sraverify-0.1.0.dist-info/entry_points.txt +2 -0
- sraverify-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""Check if Security Lake SQS queues are encrypted with CMK."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_02(SecurityLakeCheck):
|
|
9
|
+
"""Check if Security Lake SQS queues are encrypted with CMK."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-SECURITYLAKE-02"
|
|
15
|
+
self.check_name = "Security Lake SQS queues encrypted with CMK"
|
|
16
|
+
self.severity = "HIGH"
|
|
17
|
+
self.description = (
|
|
18
|
+
"This check verifies whether Security Lake manager SQS Queues within "
|
|
19
|
+
"delegated admin account is encrypted with a customer managed key from "
|
|
20
|
+
"AWS KMS. These SQS queues are used by AWS Lambda function for ETL job "
|
|
21
|
+
"and also by subscribers looking for new logs deposited into the data lake. "
|
|
22
|
+
"You must use a customer managed KMS key for the encryption as you have "
|
|
23
|
+
"greater control on the key usage and permission."
|
|
24
|
+
)
|
|
25
|
+
self.check_logic = (
|
|
26
|
+
"Gets all subscribers for Security Lake in the region. "
|
|
27
|
+
"For each subscriber with an SQS endpoint, checks if the queue is encrypted with a customer managed KMS key. "
|
|
28
|
+
"The check passes if all SQS queues are encrypted with customer managed keys (not AWS managed keys). "
|
|
29
|
+
"The check fails if any SQS queue is not encrypted or uses an AWS managed key (alias/aws/*)."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
Execute the check.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
List of findings
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
for region in self.regions:
|
|
41
|
+
logger.debug(f"Checking if Security Lake SQS queues are encrypted with CMK in {region}")
|
|
42
|
+
|
|
43
|
+
# Get subscribers for the region using the base class method
|
|
44
|
+
subscribers = self.get_subscribers(region)
|
|
45
|
+
|
|
46
|
+
# Find SQS queues
|
|
47
|
+
sqs_queues = []
|
|
48
|
+
for subscriber in subscribers:
|
|
49
|
+
endpoint = subscriber.get("subscriberEndpoint", "")
|
|
50
|
+
if endpoint and "sqs" in endpoint.lower():
|
|
51
|
+
# Convert ARN to queue URL if needed
|
|
52
|
+
if endpoint.startswith("arn:aws:sqs:"):
|
|
53
|
+
# Extract components from ARN: arn:aws:sqs:region:account:queue-name
|
|
54
|
+
arn_parts = endpoint.split(":")
|
|
55
|
+
if len(arn_parts) >= 6:
|
|
56
|
+
queue_region = arn_parts[3]
|
|
57
|
+
account_id = arn_parts[4]
|
|
58
|
+
queue_name = arn_parts[5]
|
|
59
|
+
queue_url = f"https://sqs.{queue_region}.amazonaws.com/{account_id}/{queue_name}"
|
|
60
|
+
else:
|
|
61
|
+
continue
|
|
62
|
+
else:
|
|
63
|
+
queue_url = endpoint
|
|
64
|
+
queue_name = queue_url.split("/")[-1]
|
|
65
|
+
|
|
66
|
+
sqs_queues.append((queue_name, queue_url))
|
|
67
|
+
|
|
68
|
+
if not subscribers or not sqs_queues:
|
|
69
|
+
resource_id = f"arn:aws:securitylake:{region}:{self.account_id}:subscriber/none"
|
|
70
|
+
self.findings.append(
|
|
71
|
+
self.create_finding(
|
|
72
|
+
status="FAIL",
|
|
73
|
+
region=region,
|
|
74
|
+
resource_id=resource_id,
|
|
75
|
+
checked_value="SQS queues present and encrypted with CMK",
|
|
76
|
+
actual_value=f"No SQS queues found in {region}",
|
|
77
|
+
remediation=(
|
|
78
|
+
"Configure subscribers with SQS queues. In the Security Lake console, "
|
|
79
|
+
"navigate to Subscribers and add subscribers with SQS queue endpoints."
|
|
80
|
+
)
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
continue
|
|
84
|
+
|
|
85
|
+
# Check encryption for each queue
|
|
86
|
+
unencrypted_queues = []
|
|
87
|
+
for queue_name, queue_url in sqs_queues:
|
|
88
|
+
resource_id = f"arn:aws:sqs:{region}:{self.account_id}:{queue_name}"
|
|
89
|
+
|
|
90
|
+
# Check encryption using base class method
|
|
91
|
+
kms_key = self.get_sqs_queue_encryption(region, queue_url)
|
|
92
|
+
|
|
93
|
+
if not kms_key or kms_key.startswith("alias/aws/"):
|
|
94
|
+
unencrypted_queues.append((queue_name, queue_url))
|
|
95
|
+
|
|
96
|
+
if unencrypted_queues:
|
|
97
|
+
# Use the first unencrypted queue for the resource ID
|
|
98
|
+
queue_name = unencrypted_queues[0][0]
|
|
99
|
+
resource_id = f"arn:aws:sqs:{region}:{self.account_id}:{queue_name}"
|
|
100
|
+
|
|
101
|
+
logger.debug(f"Found {len(unencrypted_queues)} unencrypted SQS queues in {region}")
|
|
102
|
+
self.findings.append(
|
|
103
|
+
self.create_finding(
|
|
104
|
+
status="FAIL",
|
|
105
|
+
region=region,
|
|
106
|
+
resource_id=resource_id,
|
|
107
|
+
checked_value="All SQS queues encrypted with CMK",
|
|
108
|
+
actual_value=f"The following SQS queues are not encrypted with CMK: {', '.join([name for name, _ in unencrypted_queues])}",
|
|
109
|
+
remediation=(
|
|
110
|
+
"Configure SQS queue encryption with a customer managed KMS key. In the SQS console, "
|
|
111
|
+
"select each queue and under Server-side encryption, choose 'Enable server-side encryption' "
|
|
112
|
+
"and select a customer managed KMS key."
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
else:
|
|
117
|
+
# Use the first queue for the resource ID in the PASS case
|
|
118
|
+
queue_name = sqs_queues[0][0]
|
|
119
|
+
resource_id = f"arn:aws:sqs:{region}:{self.account_id}:{queue_name}"
|
|
120
|
+
|
|
121
|
+
logger.debug(f"All Security Lake SQS queues are encrypted with CMK in {region}")
|
|
122
|
+
self.findings.append(
|
|
123
|
+
self.create_finding(
|
|
124
|
+
status="PASS",
|
|
125
|
+
region=region,
|
|
126
|
+
resource_id=resource_id,
|
|
127
|
+
checked_value="All SQS queues encrypted with CMK",
|
|
128
|
+
actual_value=f"All Security Lake SQS queues are encrypted with CMK in {region}",
|
|
129
|
+
remediation="No remediation needed"
|
|
130
|
+
)
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
return self.findings
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Check if Security Lake SQS DLQ is encrypted with CMK."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_03(SecurityLakeCheck):
|
|
9
|
+
"""Check if Security Lake SQS DLQ is encrypted with CMK."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-SECURITYLAKE-03"
|
|
15
|
+
self.check_name = "Security Lake DLQ encrypted with CMK"
|
|
16
|
+
self.severity = "HIGH"
|
|
17
|
+
self.description = (
|
|
18
|
+
"This check verifies whether Security Lake SQS DLQ is encrypted in this "
|
|
19
|
+
"region with a customer managed key from AWS KMS. You must use a customer "
|
|
20
|
+
"managed KMS key for the encryption as you have greater control on the key "
|
|
21
|
+
"usage and permission."
|
|
22
|
+
)
|
|
23
|
+
self.check_logic = (
|
|
24
|
+
"Gets all subscribers for Security Lake in the region. "
|
|
25
|
+
"For each subscriber with a DLQ endpoint, checks if the queue is encrypted with a customer managed KMS key. "
|
|
26
|
+
"The check passes if all DLQ queues are encrypted with customer managed keys (not AWS managed keys). "
|
|
27
|
+
"The check fails if any DLQ queue is not encrypted or uses an AWS managed key (alias/aws/*)."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
31
|
+
"""
|
|
32
|
+
Execute the check.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
List of findings
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
for region in self.regions:
|
|
39
|
+
logger.debug(f"Checking if Security Lake SQS DLQ is encrypted with CMK in {region}")
|
|
40
|
+
|
|
41
|
+
# Get subscribers for the region using the base class method
|
|
42
|
+
subscribers = self.get_subscribers(region)
|
|
43
|
+
|
|
44
|
+
# Find DLQ queues
|
|
45
|
+
dlq_queues = []
|
|
46
|
+
for subscriber in subscribers:
|
|
47
|
+
endpoint = subscriber.get("subscriberEndpoint", "")
|
|
48
|
+
if endpoint and "sqs" in endpoint.lower() and "dlq" in endpoint.lower():
|
|
49
|
+
queue_url = endpoint
|
|
50
|
+
queue_name = queue_url.split("/")[-1]
|
|
51
|
+
dlq_queues.append((queue_name, queue_url))
|
|
52
|
+
|
|
53
|
+
if not subscribers or not dlq_queues:
|
|
54
|
+
resource_id = f"arn:aws:securitylake:{region}:{self.account_id}:dlq/none"
|
|
55
|
+
self.findings.append(
|
|
56
|
+
self.create_finding(
|
|
57
|
+
status="FAIL",
|
|
58
|
+
region=region,
|
|
59
|
+
resource_id=resource_id,
|
|
60
|
+
checked_value="DLQ queues present and encrypted with CMK",
|
|
61
|
+
actual_value=f"No DLQ queues found - Security Lake may not be enabled in {region}",
|
|
62
|
+
remediation=(
|
|
63
|
+
"Enable Security Lake and configure subscribers with DLQ queues. In the Security Lake console, "
|
|
64
|
+
"navigate to Subscribers and add subscribers with DLQ queue endpoints."
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
# Check encryption for each queue
|
|
71
|
+
unencrypted_dlqs = []
|
|
72
|
+
for queue_name, queue_url in dlq_queues:
|
|
73
|
+
# Check encryption using base class method
|
|
74
|
+
kms_key = self.get_sqs_queue_encryption(region, queue_url)
|
|
75
|
+
|
|
76
|
+
if not kms_key or kms_key.startswith("alias/aws/"):
|
|
77
|
+
unencrypted_dlqs.append((queue_name, queue_url))
|
|
78
|
+
|
|
79
|
+
if unencrypted_dlqs:
|
|
80
|
+
# Use the first unencrypted queue for the resource ID
|
|
81
|
+
queue_name = unencrypted_dlqs[0][0]
|
|
82
|
+
resource_id = f"arn:aws:sqs:{region}:{self.account_id}:{queue_name}"
|
|
83
|
+
|
|
84
|
+
logger.debug(f"Found {len(unencrypted_dlqs)} unencrypted DLQ queues in {region}")
|
|
85
|
+
self.findings.append(
|
|
86
|
+
self.create_finding(
|
|
87
|
+
status="FAIL",
|
|
88
|
+
region=region,
|
|
89
|
+
resource_id=resource_id,
|
|
90
|
+
checked_value="All DLQ queues encrypted with CMK",
|
|
91
|
+
actual_value=f"The following DLQ queues are not encrypted with CMK: {', '.join([name for name, _ in unencrypted_dlqs])}",
|
|
92
|
+
remediation=(
|
|
93
|
+
"Configure DLQ queue encryption with a customer managed KMS key. In the SQS console, "
|
|
94
|
+
"select each DLQ queue and under Server-side encryption, choose 'Enable server-side encryption' "
|
|
95
|
+
"and select a customer managed KMS key."
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
# Use the first queue for the resource ID in the PASS case
|
|
101
|
+
queue_name = dlq_queues[0][0]
|
|
102
|
+
resource_id = f"arn:aws:sqs:{region}:{self.account_id}:{queue_name}"
|
|
103
|
+
|
|
104
|
+
logger.debug(f"All Security Lake DLQ queues are encrypted with CMK in {region}")
|
|
105
|
+
self.findings.append(
|
|
106
|
+
self.create_finding(
|
|
107
|
+
status="PASS",
|
|
108
|
+
region=region,
|
|
109
|
+
resource_id=resource_id,
|
|
110
|
+
checked_value="All DLQ queues encrypted with CMK",
|
|
111
|
+
actual_value=f"All Security Lake DLQ queues are encrypted with CMK in {region}",
|
|
112
|
+
remediation="No remediation needed"
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return self.findings
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""Check if Security Lake organization configuration is enabled."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_04(SecurityLakeCheck):
|
|
9
|
+
"""Check if Security Lake organization configuration is enabled."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-SECURITYLAKE-04"
|
|
15
|
+
self.check_name = "Security Lake organization configuration enabled"
|
|
16
|
+
self.severity = "HIGH"
|
|
17
|
+
self.description = (
|
|
18
|
+
"This check verifies whether Amazon Security Lake has configuration that "
|
|
19
|
+
"will automatically enable new organization accounts as member accounts "
|
|
20
|
+
"from an Amazon Security Lake administrator account."
|
|
21
|
+
)
|
|
22
|
+
self.check_logic = (
|
|
23
|
+
"Gets the organization configuration for Security Lake in the region. "
|
|
24
|
+
"The check passes if organization configuration exists, indicating that "
|
|
25
|
+
"Security Lake is configured to automatically enable new organization accounts. "
|
|
26
|
+
"The check fails if no organization configuration is found."
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
30
|
+
"""
|
|
31
|
+
Execute the check.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
List of findings
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
for region in self.regions:
|
|
38
|
+
logger.debug(f"Checking if Security Lake organization configuration is enabled in {region}")
|
|
39
|
+
resource_id = f"arn:aws:securitylake:{region}:{self.account_id}:organization-configuration/default"
|
|
40
|
+
|
|
41
|
+
# Get organization configuration using the base class method
|
|
42
|
+
config = self.get_organization_configuration(region)
|
|
43
|
+
|
|
44
|
+
if not config:
|
|
45
|
+
self.findings.append(
|
|
46
|
+
self.create_finding(
|
|
47
|
+
status="FAIL",
|
|
48
|
+
region=region,
|
|
49
|
+
resource_id=resource_id,
|
|
50
|
+
checked_value="Organization configuration enabled",
|
|
51
|
+
actual_value=f"Security Lake organization configuration is not enabled in {region}",
|
|
52
|
+
remediation=(
|
|
53
|
+
"Enable Security Lake organization configuration. In the Security Lake console, "
|
|
54
|
+
"navigate to Settings > Organization Configuration and enable organization configuration. "
|
|
55
|
+
"Alternatively, use the AWS CLI command: "
|
|
56
|
+
f"aws securitylake enable-organization-configuration --region {region}"
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
else:
|
|
61
|
+
self.findings.append(
|
|
62
|
+
self.create_finding(
|
|
63
|
+
status="PASS",
|
|
64
|
+
region=region,
|
|
65
|
+
resource_id=resource_id,
|
|
66
|
+
checked_value="Organization configuration enabled",
|
|
67
|
+
actual_value=f"Security Lake organization configuration is enabled in {region}",
|
|
68
|
+
remediation="No remediation needed"
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return self.findings
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Check if Security Lake organization auto-enable configuration matches AWS defaults."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_05(SecurityLakeCheck):
|
|
9
|
+
"""Check if Security Lake organization auto-enable configuration matches AWS defaults."""
|
|
10
|
+
|
|
11
|
+
# AWS default/recommended log sources for new accounts
|
|
12
|
+
AWS_DEFAULT_LOG_SOURCES = {
|
|
13
|
+
"CLOUD_TRAIL_MGMT",
|
|
14
|
+
"LAMBDA_EXECUTION",
|
|
15
|
+
"EKS_AUDIT",
|
|
16
|
+
"ROUTE53",
|
|
17
|
+
"SH_FINDINGS",
|
|
18
|
+
"VPC_FLOW"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
"""Initialize check."""
|
|
23
|
+
super().__init__()
|
|
24
|
+
self.account_type = "log-archive" # Organization config managed by delegated admin
|
|
25
|
+
self.check_id = "SRA-SECURITYLAKE-05"
|
|
26
|
+
self.check_name = "Security Lake organization auto-enable matches AWS defaults"
|
|
27
|
+
self.severity = "MEDIUM"
|
|
28
|
+
self.description = (
|
|
29
|
+
"This check verifies whether Amazon Security Lake organization auto-enable "
|
|
30
|
+
"configuration matches AWS default/recommended log sources for new accounts "
|
|
31
|
+
"(CLOUD_TRAIL_MGMT, LAMBDA_EXECUTION, EKS_AUDIT, ROUTE53, SH_FINDINGS, VPC_FLOW). "
|
|
32
|
+
"S3_DATA and WAF are excluded as they are optional due to high volume."
|
|
33
|
+
)
|
|
34
|
+
self.check_logic = (
|
|
35
|
+
"Gets the organization configuration for Security Lake auto-enable settings. "
|
|
36
|
+
"The check passes if all AWS default log sources are configured for auto-enable. "
|
|
37
|
+
"The check fails if any default log sources are missing from auto-enable configuration."
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
41
|
+
"""
|
|
42
|
+
Execute the check.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
List of findings
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
for region in self.regions:
|
|
49
|
+
logger.debug(f"Checking Security Lake organization auto-enable configuration in {region}")
|
|
50
|
+
resource_id = f"arn:aws:securitylake:{region}:{self.account_id}:organization-configuration/auto-enable"
|
|
51
|
+
|
|
52
|
+
# Get organization configuration using the base class method
|
|
53
|
+
config = self.get_organization_configuration(region)
|
|
54
|
+
|
|
55
|
+
if not config:
|
|
56
|
+
self.findings.append(
|
|
57
|
+
self.create_finding(
|
|
58
|
+
status="FAIL",
|
|
59
|
+
region=region,
|
|
60
|
+
resource_id=resource_id,
|
|
61
|
+
checked_value=f"Auto-enable configured with AWS defaults: {', '.join(sorted(self.AWS_DEFAULT_LOG_SOURCES))}",
|
|
62
|
+
actual_value=f"No organization configuration found in {region}",
|
|
63
|
+
remediation=(
|
|
64
|
+
"Configure Security Lake organization auto-enable settings. In the Security Lake console, "
|
|
65
|
+
"navigate to Settings > Organization Configuration and enable auto-enable for new accounts "
|
|
66
|
+
"with the AWS default log sources."
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
# Extract auto-enable sources from configuration
|
|
73
|
+
auto_enable_sources = set()
|
|
74
|
+
auto_enable_config = config.get("autoEnableNewAccount", [])
|
|
75
|
+
|
|
76
|
+
# Find the configuration for this region
|
|
77
|
+
for region_config in auto_enable_config:
|
|
78
|
+
if region_config.get("region") == region:
|
|
79
|
+
sources = region_config.get("sources", [])
|
|
80
|
+
for source in sources:
|
|
81
|
+
source_name = source.get("sourceName")
|
|
82
|
+
if source_name:
|
|
83
|
+
auto_enable_sources.add(source_name)
|
|
84
|
+
break
|
|
85
|
+
|
|
86
|
+
missing_sources = self.AWS_DEFAULT_LOG_SOURCES - auto_enable_sources
|
|
87
|
+
|
|
88
|
+
if missing_sources:
|
|
89
|
+
actual_configured = ', '.join(sorted(auto_enable_sources)) if auto_enable_sources else "None"
|
|
90
|
+
self.findings.append(
|
|
91
|
+
self.create_finding(
|
|
92
|
+
status="FAIL",
|
|
93
|
+
region=region,
|
|
94
|
+
resource_id=resource_id,
|
|
95
|
+
checked_value=f"Auto-enable configured with AWS defaults: {', '.join(sorted(self.AWS_DEFAULT_LOG_SOURCES))}",
|
|
96
|
+
actual_value=f"Currently configured: {actual_configured}. Missing: {', '.join(sorted(missing_sources))}",
|
|
97
|
+
remediation=(
|
|
98
|
+
"Update Security Lake organization auto-enable configuration to include missing sources. "
|
|
99
|
+
"In the Security Lake console, navigate to Settings > Organization Configuration and "
|
|
100
|
+
f"add the missing sources: {', '.join(sorted(missing_sources))}."
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
else:
|
|
105
|
+
self.findings.append(
|
|
106
|
+
self.create_finding(
|
|
107
|
+
status="PASS",
|
|
108
|
+
region=region,
|
|
109
|
+
resource_id=resource_id,
|
|
110
|
+
checked_value=f"Auto-enable configured with AWS defaults: {', '.join(sorted(self.AWS_DEFAULT_LOG_SOURCES))}",
|
|
111
|
+
actual_value=f"Currently configured: {', '.join(sorted(auto_enable_sources))}",
|
|
112
|
+
remediation="No remediation needed"
|
|
113
|
+
)
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return self.findings
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Check if Route 53 log source is enabled for Security Lake."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_06(SecurityLakeCheck):
|
|
9
|
+
"""Check if Route 53 log source is enabled for Security Lake."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.account_type = "log-archive" # Check from log archive account
|
|
15
|
+
self.check_id = "SRA-SECURITYLAKE-06"
|
|
16
|
+
self.check_name = "Security Lake Route 53 log source enabled with version 2.0 for all organization accounts"
|
|
17
|
+
self.severity = "HIGH"
|
|
18
|
+
self.description = (
|
|
19
|
+
"This check verifies whether Amazon Security Lake is configured with "
|
|
20
|
+
"Route 53 log and event source version 2.0 for all active accounts in the organization. "
|
|
21
|
+
"Route 53 resolver query logs track DNS queries made by resources within Amazon VPC. "
|
|
22
|
+
"Security Lake collects resolver query logs directly from Route 53 through an independent "
|
|
23
|
+
"and duplicated stream of events. This check runs from the delegated administrator account "
|
|
24
|
+
"and validates configuration across all organization member accounts."
|
|
25
|
+
)
|
|
26
|
+
self.check_logic = (
|
|
27
|
+
"Checks if the Route 53 log source is enabled in Security Lake with version 2.0. "
|
|
28
|
+
"The check passes if the ROUTE53 log source is configured. "
|
|
29
|
+
"The check fails if the ROUTE53 log source is not configured."
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
33
|
+
"""
|
|
34
|
+
Execute the check.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
List of findings
|
|
38
|
+
"""
|
|
39
|
+
for region in self.regions:
|
|
40
|
+
logger.debug(f"Checking if Route 53 log source is enabled in {region}")
|
|
41
|
+
|
|
42
|
+
# Get all organization accounts to check
|
|
43
|
+
org_accounts = self.get_organization_accounts(region)
|
|
44
|
+
if not org_accounts:
|
|
45
|
+
logger.warning("No organization accounts found")
|
|
46
|
+
org_accounts = [self.account_id] # Fall back to current account
|
|
47
|
+
|
|
48
|
+
# Create sets of active account IDs
|
|
49
|
+
active_org_account_ids = set()
|
|
50
|
+
for account in org_accounts:
|
|
51
|
+
if account.get('Status') == 'ACTIVE':
|
|
52
|
+
active_org_account_ids.add(account.get('Id'))
|
|
53
|
+
|
|
54
|
+
# Check each account in the organization
|
|
55
|
+
for account_id in active_org_account_ids:
|
|
56
|
+
resource_id = f"arn:aws:securitylake:{region}:{account_id}:log-source/ROUTE53"
|
|
57
|
+
|
|
58
|
+
# Check Route 53 log source configuration (call API once, check both versions)
|
|
59
|
+
route53_v2_enabled = self.check_log_source_configured(region, "ROUTE53", account_id, "2.0")
|
|
60
|
+
|
|
61
|
+
if not route53_v2_enabled:
|
|
62
|
+
# Only check v1.0 if v2.0 is not enabled (uses cached data)
|
|
63
|
+
route53_v1_enabled = self.check_log_source_configured(region, "ROUTE53", account_id, "1.0")
|
|
64
|
+
|
|
65
|
+
if route53_v1_enabled:
|
|
66
|
+
actual_value = f"Route 53 log source is configured with version 1.0 instead of 2.0 for account {account_id}"
|
|
67
|
+
remediation = (
|
|
68
|
+
f"Update Route 53 log source to version 2.0 for account {account_id}. "
|
|
69
|
+
"In the Security Lake console, navigate to Sources and update the Route 53 source version. "
|
|
70
|
+
"Alternatively, use the AWS CLI command: "
|
|
71
|
+
f"aws securitylake update-data-lake --sources '[{{\"regions\":[\"{region}\"],\"sourceName\":\"ROUTE53\",\"sourceVersion\":\"2.0\"}}]' --region {region}"
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
actual_value = f"Route 53 log source is not configured for account {account_id}"
|
|
75
|
+
remediation = (
|
|
76
|
+
"Enable Route 53 log source in Security Lake. In the Security Lake console, "
|
|
77
|
+
"navigate to Settings > Log Sources and enable Route 53 logs. "
|
|
78
|
+
"Alternatively, use the AWS CLI command: "
|
|
79
|
+
f"aws securitylake create-aws-log-source --sources '[{{\"regions\":[\"{region}\"],\"sourceName\":\"ROUTE53\",\"sourceVersion\":\"2.0\"}}]' --region {region}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.findings.append(
|
|
83
|
+
self.create_finding(
|
|
84
|
+
status="FAIL",
|
|
85
|
+
region=region,
|
|
86
|
+
resource_id=resource_id,
|
|
87
|
+
checked_value="Route 53 log source enabled with version 2.0",
|
|
88
|
+
actual_value=actual_value,
|
|
89
|
+
remediation=remediation
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
else:
|
|
93
|
+
self.findings.append(
|
|
94
|
+
self.create_finding(
|
|
95
|
+
status="PASS",
|
|
96
|
+
region=region,
|
|
97
|
+
resource_id=resource_id,
|
|
98
|
+
checked_value="Route 53 log source enabled with version 2.0",
|
|
99
|
+
actual_value=f"Route 53 log source is configured in {region} for account {account_id}",
|
|
100
|
+
remediation="No remediation needed"
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
return self.findings
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""Check if CloudTrail S3 data events are enabled for Security Lake."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
from sraverify.services.securitylake.base import SecurityLakeCheck
|
|
5
|
+
from sraverify.core.logging import logger
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_SECURITYLAKE_07(SecurityLakeCheck):
|
|
9
|
+
"""Check if CloudTrail S3 data events are enabled for Security Lake."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.account_type = "log-archive" # Check all org accounts from delegated admin
|
|
15
|
+
self.check_id = "SRA-SECURITYLAKE-07"
|
|
16
|
+
self.check_name = "Security Lake CloudTrail S3 data events enabled with version 2.0 for all organization accounts"
|
|
17
|
+
self.severity = "HIGH"
|
|
18
|
+
self.description = (
|
|
19
|
+
"This check verifies whether Amazon Security Lake is configured with "
|
|
20
|
+
"CloudTrail data event for S3 log and event source version 2.0 for all active accounts in the organization. "
|
|
21
|
+
"CloudTrail data events, also known as data plane operations, show "
|
|
22
|
+
"the resource operations performed on or within resources in your AWS "
|
|
23
|
+
"account. These operations are often high-volume activities and should "
|
|
24
|
+
"be enabled as per your requirement. Security Lake pulls data directly "
|
|
25
|
+
"from S3 through an independent and duplicated stream of events. "
|
|
26
|
+
"This check runs from the delegated administrator account "
|
|
27
|
+
"and validates configuration across all organization member accounts."
|
|
28
|
+
)
|
|
29
|
+
self.check_logic = (
|
|
30
|
+
"Checks if the CloudTrail S3 data events log source version 2.0 is enabled in Security Lake "
|
|
31
|
+
"for all active organization accounts. The check passes if the S3_DATA log source version 2.0 is enabled. "
|
|
32
|
+
"The check fails if the S3_DATA log source is not enabled or configured with version 1.0."
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
36
|
+
"""
|
|
37
|
+
Execute the check.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
List of findings
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
for region in self.regions:
|
|
44
|
+
logger.debug(f"Checking if CloudTrail S3 data events are enabled in {region}")
|
|
45
|
+
|
|
46
|
+
# Get all organization accounts
|
|
47
|
+
org_accounts = self.get_organization_accounts(region)
|
|
48
|
+
if not org_accounts:
|
|
49
|
+
logger.debug("No organization accounts found, checking current account only")
|
|
50
|
+
org_accounts = [{'Id': self.account_id, 'Status': 'ACTIVE'}]
|
|
51
|
+
|
|
52
|
+
# Create sets of active account IDs
|
|
53
|
+
active_org_account_ids = set()
|
|
54
|
+
for account in org_accounts:
|
|
55
|
+
if account.get('Status') == 'ACTIVE':
|
|
56
|
+
active_org_account_ids.add(account.get('Id'))
|
|
57
|
+
|
|
58
|
+
# Check each account in the organization
|
|
59
|
+
for account_id in active_org_account_ids:
|
|
60
|
+
resource_id = f"arn:aws:securitylake:{region}:{account_id}:log-source/S3_DATA"
|
|
61
|
+
|
|
62
|
+
# Check CloudTrail S3 data events configuration
|
|
63
|
+
s3_data_v2_enabled = self.check_log_source_configured(region, "S3_DATA", account_id, "2.0")
|
|
64
|
+
|
|
65
|
+
if not s3_data_v2_enabled:
|
|
66
|
+
# Only check v1.0 if v2.0 is not enabled (uses cached data)
|
|
67
|
+
s3_data_v1_enabled = self.check_log_source_configured(region, "S3_DATA", account_id, "1.0")
|
|
68
|
+
|
|
69
|
+
if s3_data_v1_enabled:
|
|
70
|
+
actual_value = f"CloudTrail S3 data events are configured with version 1.0 instead of 2.0 for account {account_id}"
|
|
71
|
+
remediation = (
|
|
72
|
+
f"Update CloudTrail S3 data events to version 2.0 for account {account_id}. "
|
|
73
|
+
"In the Security Lake console, navigate to Sources and update the S3 data events source version. "
|
|
74
|
+
"Alternatively, use the AWS CLI command: "
|
|
75
|
+
f"aws securitylake update-data-lake --sources '[{{\"regions\":[\"{region}\"],\"sourceName\":\"S3_DATA\",\"sourceVersion\":\"2.0\"}}]' --region {region}"
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
78
|
+
actual_value = f"CloudTrail S3 data events are not configured for account {account_id}"
|
|
79
|
+
remediation = (
|
|
80
|
+
"Enable CloudTrail S3 data events in Security Lake. In the Security Lake console, "
|
|
81
|
+
"navigate to Settings > Log Sources and enable CloudTrail S3 data events. "
|
|
82
|
+
"Alternatively, use the AWS CLI command: "
|
|
83
|
+
f"aws securitylake create-aws-log-source --sources '[{{\"regions\":[\"{region}\"],\"sourceName\":\"S3_DATA\",\"sourceVersion\":\"2.0\"}}]' --region {region}"
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
self.findings.append(
|
|
87
|
+
self.create_finding(
|
|
88
|
+
status="FAIL",
|
|
89
|
+
region=region,
|
|
90
|
+
resource_id=resource_id,
|
|
91
|
+
checked_value="CloudTrail S3 data events enabled with version 2.0",
|
|
92
|
+
actual_value=actual_value,
|
|
93
|
+
remediation=remediation
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
else:
|
|
97
|
+
self.findings.append(
|
|
98
|
+
self.create_finding(
|
|
99
|
+
status="PASS",
|
|
100
|
+
region=region,
|
|
101
|
+
resource_id=resource_id,
|
|
102
|
+
checked_value="CloudTrail S3 data events enabled with version 2.0",
|
|
103
|
+
actual_value=f"CloudTrail S3 data events are enabled with version 2.0 in {region} for account {account_id}",
|
|
104
|
+
remediation="No remediation needed"
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
return self.findings
|