regscale-cli 6.27.2.0__py3-none-any.whl → 6.28.0.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.
Potentially problematic release.
This version of regscale-cli might be problematic. Click here for more details.
- regscale/_version.py +1 -1
- regscale/core/app/application.py +1 -0
- regscale/core/app/internal/control_editor.py +73 -21
- regscale/core/app/internal/login.py +4 -1
- regscale/core/app/internal/model_editor.py +219 -64
- regscale/core/app/utils/app_utils.py +11 -2
- regscale/core/login.py +21 -4
- regscale/core/utils/date.py +77 -1
- regscale/dev/cli.py +26 -0
- regscale/dev/version.py +72 -0
- regscale/integrations/commercial/__init__.py +15 -1
- regscale/integrations/commercial/amazon/amazon/__init__.py +0 -0
- regscale/integrations/commercial/amazon/amazon/common.py +204 -0
- regscale/integrations/commercial/amazon/common.py +48 -58
- regscale/integrations/commercial/aws/audit_manager_compliance.py +2671 -0
- regscale/integrations/commercial/aws/cli.py +3093 -55
- regscale/integrations/commercial/aws/cloudtrail_control_mappings.py +333 -0
- regscale/integrations/commercial/aws/cloudtrail_evidence.py +501 -0
- regscale/integrations/commercial/aws/cloudwatch_control_mappings.py +357 -0
- regscale/integrations/commercial/aws/cloudwatch_evidence.py +490 -0
- regscale/integrations/commercial/aws/config_compliance.py +914 -0
- regscale/integrations/commercial/aws/conformance_pack_mappings.py +198 -0
- regscale/integrations/commercial/aws/evidence_generator.py +283 -0
- regscale/integrations/commercial/aws/guardduty_control_mappings.py +340 -0
- regscale/integrations/commercial/aws/guardduty_evidence.py +1053 -0
- regscale/integrations/commercial/aws/iam_control_mappings.py +368 -0
- regscale/integrations/commercial/aws/iam_evidence.py +574 -0
- regscale/integrations/commercial/aws/inventory/__init__.py +223 -22
- regscale/integrations/commercial/aws/inventory/base.py +107 -5
- regscale/integrations/commercial/aws/inventory/resources/audit_manager.py +513 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail.py +315 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudtrail_logs_metadata.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/cloudwatch.py +191 -0
- regscale/integrations/commercial/aws/inventory/resources/compute.py +66 -9
- regscale/integrations/commercial/aws/inventory/resources/config.py +464 -0
- regscale/integrations/commercial/aws/inventory/resources/containers.py +74 -9
- regscale/integrations/commercial/aws/inventory/resources/database.py +106 -31
- regscale/integrations/commercial/aws/inventory/resources/guardduty.py +286 -0
- regscale/integrations/commercial/aws/inventory/resources/iam.py +470 -0
- regscale/integrations/commercial/aws/inventory/resources/inspector.py +476 -0
- regscale/integrations/commercial/aws/inventory/resources/integration.py +175 -61
- regscale/integrations/commercial/aws/inventory/resources/kms.py +447 -0
- regscale/integrations/commercial/aws/inventory/resources/networking.py +103 -67
- regscale/integrations/commercial/aws/inventory/resources/s3.py +394 -0
- regscale/integrations/commercial/aws/inventory/resources/security.py +268 -72
- regscale/integrations/commercial/aws/inventory/resources/securityhub.py +473 -0
- regscale/integrations/commercial/aws/inventory/resources/storage.py +53 -29
- regscale/integrations/commercial/aws/inventory/resources/systems_manager.py +657 -0
- regscale/integrations/commercial/aws/inventory/resources/vpc.py +655 -0
- regscale/integrations/commercial/aws/kms_control_mappings.py +288 -0
- regscale/integrations/commercial/aws/kms_evidence.py +879 -0
- regscale/integrations/commercial/aws/ocsf/__init__.py +7 -0
- regscale/integrations/commercial/aws/ocsf/constants.py +115 -0
- regscale/integrations/commercial/aws/ocsf/mapper.py +435 -0
- regscale/integrations/commercial/aws/org_control_mappings.py +286 -0
- regscale/integrations/commercial/aws/org_evidence.py +666 -0
- regscale/integrations/commercial/aws/s3_control_mappings.py +356 -0
- regscale/integrations/commercial/aws/s3_evidence.py +632 -0
- regscale/integrations/commercial/aws/scanner.py +853 -205
- regscale/integrations/commercial/aws/security_hub.py +319 -0
- regscale/integrations/commercial/aws/session_manager.py +282 -0
- regscale/integrations/commercial/aws/ssm_control_mappings.py +291 -0
- regscale/integrations/commercial/aws/ssm_evidence.py +492 -0
- regscale/integrations/commercial/synqly/query_builder.py +4 -1
- regscale/integrations/compliance_integration.py +308 -38
- regscale/integrations/control_matcher.py +78 -23
- regscale/integrations/due_date_handler.py +3 -0
- regscale/integrations/public/csam/csam.py +572 -763
- regscale/integrations/public/csam/csam_agency_defined.py +179 -0
- regscale/integrations/public/csam/csam_common.py +154 -0
- regscale/integrations/public/csam/csam_controls.py +432 -0
- regscale/integrations/public/csam/csam_poam.py +124 -0
- regscale/integrations/public/fedramp/click.py +17 -4
- regscale/integrations/public/fedramp/fedramp_cis_crm.py +271 -62
- regscale/integrations/public/fedramp/poam/scanner.py +74 -7
- regscale/integrations/scanner_integration.py +415 -85
- regscale/models/integration_models/cisa_kev_data.json +80 -20
- regscale/models/integration_models/synqly_models/capabilities.json +1 -1
- regscale/models/integration_models/synqly_models/connectors/vulnerabilities.py +44 -3
- regscale/models/integration_models/synqly_models/ocsf_mapper.py +41 -12
- regscale/models/platform.py +3 -0
- regscale/models/regscale_models/__init__.py +5 -0
- regscale/models/regscale_models/assessment.py +2 -1
- regscale/models/regscale_models/component.py +1 -1
- regscale/models/regscale_models/control_implementation.py +55 -24
- regscale/models/regscale_models/control_objective.py +74 -5
- regscale/models/regscale_models/file.py +2 -0
- regscale/models/regscale_models/issue.py +2 -5
- regscale/models/regscale_models/organization.py +3 -0
- regscale/models/regscale_models/regscale_model.py +17 -5
- regscale/models/regscale_models/security_plan.py +1 -0
- regscale/regscale.py +11 -1
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/METADATA +1 -1
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/RECORD +140 -57
- tests/regscale/core/test_login.py +171 -4
- tests/regscale/integrations/commercial/aws/__init__.py +0 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_compliance.py +1304 -0
- tests/regscale/integrations/commercial/aws/test_audit_manager_evidence_aggregation.py +341 -0
- tests/regscale/integrations/commercial/aws/test_aws_audit_manager_collector.py +1155 -0
- tests/regscale/integrations/commercial/aws/test_aws_cloudtrail_collector.py +534 -0
- tests/regscale/integrations/commercial/aws/test_aws_config_collector.py +400 -0
- tests/regscale/integrations/commercial/aws/test_aws_guardduty_collector.py +315 -0
- tests/regscale/integrations/commercial/aws/test_aws_iam_collector.py +458 -0
- tests/regscale/integrations/commercial/aws/test_aws_inspector_collector.py +353 -0
- tests/regscale/integrations/commercial/aws/test_aws_inventory_integration.py +530 -0
- tests/regscale/integrations/commercial/aws/test_aws_kms_collector.py +919 -0
- tests/regscale/integrations/commercial/aws/test_aws_s3_collector.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_scanner_integration.py +722 -0
- tests/regscale/integrations/commercial/aws/test_aws_securityhub_collector.py +792 -0
- tests/regscale/integrations/commercial/aws/test_aws_systems_manager_collector.py +918 -0
- tests/regscale/integrations/commercial/aws/test_aws_vpc_collector.py +996 -0
- tests/regscale/integrations/commercial/aws/test_cli_evidence.py +431 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_control_mappings.py +452 -0
- tests/regscale/integrations/commercial/aws/test_cloudtrail_evidence.py +788 -0
- tests/regscale/integrations/commercial/aws/test_config_compliance.py +298 -0
- tests/regscale/integrations/commercial/aws/test_conformance_pack_mappings.py +200 -0
- tests/regscale/integrations/commercial/aws/test_evidence_generator.py +386 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_control_mappings.py +564 -0
- tests/regscale/integrations/commercial/aws/test_guardduty_evidence.py +1041 -0
- tests/regscale/integrations/commercial/aws/test_iam_control_mappings.py +718 -0
- tests/regscale/integrations/commercial/aws/test_iam_evidence.py +1375 -0
- tests/regscale/integrations/commercial/aws/test_kms_control_mappings.py +656 -0
- tests/regscale/integrations/commercial/aws/test_kms_evidence.py +1163 -0
- tests/regscale/integrations/commercial/aws/test_ocsf_mapper.py +370 -0
- tests/regscale/integrations/commercial/aws/test_org_control_mappings.py +546 -0
- tests/regscale/integrations/commercial/aws/test_org_evidence.py +1240 -0
- tests/regscale/integrations/commercial/aws/test_s3_control_mappings.py +672 -0
- tests/regscale/integrations/commercial/aws/test_s3_evidence.py +987 -0
- tests/regscale/integrations/commercial/aws/test_scanner_evidence.py +373 -0
- tests/regscale/integrations/commercial/aws/test_security_hub_config_filtering.py +539 -0
- tests/regscale/integrations/commercial/aws/test_session_manager.py +516 -0
- tests/regscale/integrations/commercial/aws/test_ssm_control_mappings.py +588 -0
- tests/regscale/integrations/commercial/aws/test_ssm_evidence.py +735 -0
- tests/regscale/integrations/commercial/test_aws.py +55 -56
- tests/regscale/integrations/test_control_matcher.py +24 -0
- tests/regscale/models/test_control_implementation.py +118 -3
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/LICENSE +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/WHEEL +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/entry_points.txt +0 -0
- {regscale_cli-6.27.2.0.dist-info → regscale_cli-6.28.0.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""AWS S3 Control Mappings for RegScale Compliance Integration."""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("regscale")
|
|
9
|
+
|
|
10
|
+
# NIST 800-53 R5 Control Mappings for AWS S3
|
|
11
|
+
S3_CONTROL_MAPPINGS = {
|
|
12
|
+
"SC-13": {
|
|
13
|
+
"name": "Cryptographic Protection",
|
|
14
|
+
"description": "Implement cryptographic mechanisms to prevent unauthorized disclosure of information",
|
|
15
|
+
"checks": {
|
|
16
|
+
"encryption_at_rest": {
|
|
17
|
+
"weight": 100,
|
|
18
|
+
"pass_criteria": "All S3 buckets have server-side encryption enabled",
|
|
19
|
+
"fail_criteria": "One or more buckets lack encryption configuration",
|
|
20
|
+
},
|
|
21
|
+
"encryption_algorithm": {
|
|
22
|
+
"weight": 90,
|
|
23
|
+
"pass_criteria": "Buckets use approved encryption algorithms (AES-256, KMS)",
|
|
24
|
+
"fail_criteria": "Buckets use weak or no encryption",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
"SC-28": {
|
|
29
|
+
"name": "Protection of Information at Rest",
|
|
30
|
+
"description": "Protect the confidentiality and integrity of information at rest",
|
|
31
|
+
"checks": {
|
|
32
|
+
"bucket_encryption": {
|
|
33
|
+
"weight": 100,
|
|
34
|
+
"pass_criteria": "S3 buckets have default encryption enabled",
|
|
35
|
+
"fail_criteria": "Buckets store data without encryption",
|
|
36
|
+
},
|
|
37
|
+
"versioning_enabled": {
|
|
38
|
+
"weight": 85,
|
|
39
|
+
"pass_criteria": "Versioning enabled to protect against accidental deletion",
|
|
40
|
+
"fail_criteria": "Versioning disabled or not configured",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
"AC-3": {
|
|
45
|
+
"name": "Access Enforcement",
|
|
46
|
+
"description": "Enforce approved authorizations for logical access",
|
|
47
|
+
"checks": {
|
|
48
|
+
"public_access_blocked": {
|
|
49
|
+
"weight": 100,
|
|
50
|
+
"pass_criteria": "Public access block settings enabled on all buckets",
|
|
51
|
+
"fail_criteria": "Buckets allow public access",
|
|
52
|
+
},
|
|
53
|
+
"bucket_policy": {
|
|
54
|
+
"weight": 95,
|
|
55
|
+
"pass_criteria": "Bucket policies enforce least privilege access",
|
|
56
|
+
"fail_criteria": "Buckets have overly permissive or public policies",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
"AC-6": {
|
|
61
|
+
"name": "Least Privilege",
|
|
62
|
+
"description": "Employ the principle of least privilege",
|
|
63
|
+
"checks": {
|
|
64
|
+
"acl_configuration": {
|
|
65
|
+
"weight": 100,
|
|
66
|
+
"pass_criteria": "ACLs grant minimal necessary permissions",
|
|
67
|
+
"fail_criteria": "ACLs grant broad or public permissions",
|
|
68
|
+
},
|
|
69
|
+
"policy_restrictions": {
|
|
70
|
+
"weight": 90,
|
|
71
|
+
"pass_criteria": "Bucket policies restrict access to authorized principals only",
|
|
72
|
+
"fail_criteria": "Policies allow excessive permissions",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
"AU-2": {
|
|
77
|
+
"name": "Event Logging",
|
|
78
|
+
"description": "Identify events to be logged",
|
|
79
|
+
"checks": {
|
|
80
|
+
"access_logging": {
|
|
81
|
+
"weight": 100,
|
|
82
|
+
"pass_criteria": "S3 access logging enabled for all buckets",
|
|
83
|
+
"fail_criteria": "Buckets do not have access logging enabled",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
"AU-9": {
|
|
88
|
+
"name": "Protection of Audit Information",
|
|
89
|
+
"description": "Protect audit information and audit logging tools",
|
|
90
|
+
"checks": {
|
|
91
|
+
"log_bucket_protection": {
|
|
92
|
+
"weight": 100,
|
|
93
|
+
"pass_criteria": "Log destination buckets have restricted access and versioning",
|
|
94
|
+
"fail_criteria": "Log buckets lack protection controls",
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
"CP-9": {
|
|
99
|
+
"name": "System Backup",
|
|
100
|
+
"description": "Conduct backups of system-level and user-level information",
|
|
101
|
+
"checks": {
|
|
102
|
+
"versioning": {
|
|
103
|
+
"weight": 100,
|
|
104
|
+
"pass_criteria": "Versioning enabled to maintain data history",
|
|
105
|
+
"fail_criteria": "Versioning not enabled",
|
|
106
|
+
},
|
|
107
|
+
"replication": {
|
|
108
|
+
"weight": 85,
|
|
109
|
+
"pass_criteria": "Cross-region replication configured for critical buckets",
|
|
110
|
+
"fail_criteria": "No replication configured",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class S3ControlMapper:
|
|
118
|
+
"""Map AWS S3 bucket configurations to compliance control status."""
|
|
119
|
+
|
|
120
|
+
def __init__(self, framework: str = "NIST800-53R5"):
|
|
121
|
+
"""
|
|
122
|
+
Initialize S3 control mapper.
|
|
123
|
+
|
|
124
|
+
:param str framework: Compliance framework
|
|
125
|
+
"""
|
|
126
|
+
self.framework = framework
|
|
127
|
+
self.mappings = S3_CONTROL_MAPPINGS
|
|
128
|
+
|
|
129
|
+
def assess_bucket_compliance(self, bucket_data: Dict) -> Dict[str, str]:
|
|
130
|
+
"""
|
|
131
|
+
Assess S3 bucket compliance against all mapped controls.
|
|
132
|
+
|
|
133
|
+
:param Dict bucket_data: S3 bucket configuration data
|
|
134
|
+
:return: Dictionary mapping control IDs to compliance results (PASS/FAIL)
|
|
135
|
+
:rtype: Dict[str, str]
|
|
136
|
+
"""
|
|
137
|
+
results = {}
|
|
138
|
+
|
|
139
|
+
if self.framework == "NIST800-53R5":
|
|
140
|
+
results["SC-13"] = self._assess_sc13(bucket_data)
|
|
141
|
+
results["SC-28"] = self._assess_sc28(bucket_data)
|
|
142
|
+
results["AC-3"] = self._assess_ac3(bucket_data)
|
|
143
|
+
results["AC-6"] = self._assess_ac6(bucket_data)
|
|
144
|
+
results["AU-2"] = self._assess_au2(bucket_data)
|
|
145
|
+
results["AU-9"] = self._assess_au9(bucket_data)
|
|
146
|
+
results["CP-9"] = self._assess_cp9(bucket_data)
|
|
147
|
+
|
|
148
|
+
return results
|
|
149
|
+
|
|
150
|
+
def assess_all_buckets_compliance(self, buckets: List[Dict]) -> Dict[str, str]:
|
|
151
|
+
"""
|
|
152
|
+
Assess compliance across all S3 buckets.
|
|
153
|
+
|
|
154
|
+
:param List[Dict] buckets: List of bucket configurations
|
|
155
|
+
:return: Dictionary mapping control IDs to overall compliance results
|
|
156
|
+
:rtype: Dict[str, str]
|
|
157
|
+
"""
|
|
158
|
+
if not buckets:
|
|
159
|
+
logger.debug("No S3 buckets to assess")
|
|
160
|
+
return dict.fromkeys(self.mappings.keys(), "PASS")
|
|
161
|
+
|
|
162
|
+
# Aggregate results - if any bucket fails a control, overall result is FAIL
|
|
163
|
+
aggregated_results = {}
|
|
164
|
+
for control_id in self.mappings.keys():
|
|
165
|
+
control_results = []
|
|
166
|
+
for bucket in buckets:
|
|
167
|
+
bucket_result = self.assess_bucket_compliance(bucket)
|
|
168
|
+
control_results.append(bucket_result.get(control_id, "PASS"))
|
|
169
|
+
|
|
170
|
+
# If any bucket fails, the control fails overall
|
|
171
|
+
aggregated_results[control_id] = "FAIL" if "FAIL" in control_results else "PASS"
|
|
172
|
+
|
|
173
|
+
return aggregated_results
|
|
174
|
+
|
|
175
|
+
def _assess_sc13(self, bucket_data: Dict) -> str:
|
|
176
|
+
"""
|
|
177
|
+
Assess SC-13 (Cryptographic Protection) compliance.
|
|
178
|
+
|
|
179
|
+
:param Dict bucket_data: Bucket configuration data
|
|
180
|
+
:return: Compliance result (PASS/FAIL)
|
|
181
|
+
:rtype: str
|
|
182
|
+
"""
|
|
183
|
+
encryption = bucket_data.get("Encryption", {})
|
|
184
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
185
|
+
|
|
186
|
+
if not encryption.get("Enabled"):
|
|
187
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS SC-13: Encryption not enabled")
|
|
188
|
+
return "FAIL"
|
|
189
|
+
|
|
190
|
+
algorithm = encryption.get("Algorithm", "")
|
|
191
|
+
if algorithm not in ["AES256", "aws:kms"]:
|
|
192
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS SC-13: Weak or unknown encryption algorithm")
|
|
193
|
+
return "FAIL"
|
|
194
|
+
|
|
195
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES SC-13: Encryption enabled with {algorithm}")
|
|
196
|
+
return "PASS"
|
|
197
|
+
|
|
198
|
+
def _assess_sc28(self, bucket_data: Dict) -> str:
|
|
199
|
+
"""
|
|
200
|
+
Assess SC-28 (Protection of Information at Rest) compliance.
|
|
201
|
+
|
|
202
|
+
:param Dict bucket_data: Bucket configuration data
|
|
203
|
+
:return: Compliance result (PASS/FAIL)
|
|
204
|
+
:rtype: str
|
|
205
|
+
"""
|
|
206
|
+
encryption = bucket_data.get("Encryption", {})
|
|
207
|
+
versioning = bucket_data.get("Versioning", {})
|
|
208
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
209
|
+
|
|
210
|
+
if not encryption.get("Enabled"):
|
|
211
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS SC-28: No encryption at rest")
|
|
212
|
+
return "FAIL"
|
|
213
|
+
|
|
214
|
+
versioning_status = versioning.get("Status", "Disabled")
|
|
215
|
+
if versioning_status != "Enabled":
|
|
216
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS SC-28: Versioning not enabled")
|
|
217
|
+
return "FAIL"
|
|
218
|
+
|
|
219
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES SC-28: Encryption and versioning enabled")
|
|
220
|
+
return "PASS"
|
|
221
|
+
|
|
222
|
+
def _assess_ac3(self, bucket_data: Dict) -> str:
|
|
223
|
+
"""
|
|
224
|
+
Assess AC-3 (Access Enforcement) compliance.
|
|
225
|
+
|
|
226
|
+
:param Dict bucket_data: Bucket configuration data
|
|
227
|
+
:return: Compliance result (PASS/FAIL)
|
|
228
|
+
:rtype: str
|
|
229
|
+
"""
|
|
230
|
+
public_access_block = bucket_data.get("PublicAccessBlock", {})
|
|
231
|
+
policy_status = bucket_data.get("PolicyStatus", {})
|
|
232
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
233
|
+
|
|
234
|
+
# Check if all public access block settings are enabled
|
|
235
|
+
required_blocks = ["BlockPublicAcls", "IgnorePublicAcls", "BlockPublicPolicy", "RestrictPublicBuckets"]
|
|
236
|
+
for block_setting in required_blocks:
|
|
237
|
+
if not public_access_block.get(block_setting, False):
|
|
238
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS AC-3: {block_setting} not enabled")
|
|
239
|
+
return "FAIL"
|
|
240
|
+
|
|
241
|
+
# Check if bucket policy is public
|
|
242
|
+
if policy_status.get("IsPublic", False):
|
|
243
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS AC-3: Bucket has public policy")
|
|
244
|
+
return "FAIL"
|
|
245
|
+
|
|
246
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES AC-3: Public access properly blocked")
|
|
247
|
+
return "PASS"
|
|
248
|
+
|
|
249
|
+
def _assess_ac6(self, bucket_data: Dict) -> str:
|
|
250
|
+
"""
|
|
251
|
+
Assess AC-6 (Least Privilege) compliance.
|
|
252
|
+
|
|
253
|
+
:param Dict bucket_data: Bucket configuration data
|
|
254
|
+
:return: Compliance result (PASS/FAIL)
|
|
255
|
+
:rtype: str
|
|
256
|
+
"""
|
|
257
|
+
acl = bucket_data.get("ACL", {})
|
|
258
|
+
policy_status = bucket_data.get("PolicyStatus", {})
|
|
259
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
260
|
+
|
|
261
|
+
# Check for excessive ACL grants
|
|
262
|
+
grant_count = acl.get("GrantCount", 0)
|
|
263
|
+
if grant_count > 5:
|
|
264
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS AC-6: Excessive ACL grants ({grant_count})")
|
|
265
|
+
return "FAIL"
|
|
266
|
+
|
|
267
|
+
# Check for public policy
|
|
268
|
+
if policy_status.get("IsPublic", False):
|
|
269
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS AC-6: Public bucket policy violates least privilege")
|
|
270
|
+
return "FAIL"
|
|
271
|
+
|
|
272
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES AC-6: Least privilege maintained")
|
|
273
|
+
return "PASS"
|
|
274
|
+
|
|
275
|
+
def _assess_au2(self, bucket_data: Dict) -> str:
|
|
276
|
+
"""
|
|
277
|
+
Assess AU-2 (Event Logging) compliance.
|
|
278
|
+
|
|
279
|
+
:param Dict bucket_data: Bucket configuration data
|
|
280
|
+
:return: Compliance result (PASS/FAIL)
|
|
281
|
+
:rtype: str
|
|
282
|
+
"""
|
|
283
|
+
logging_config = bucket_data.get("Logging", {})
|
|
284
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
285
|
+
|
|
286
|
+
if not logging_config.get("Enabled", False):
|
|
287
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS AU-2: Access logging not enabled")
|
|
288
|
+
return "FAIL"
|
|
289
|
+
|
|
290
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES AU-2: Access logging enabled")
|
|
291
|
+
return "PASS"
|
|
292
|
+
|
|
293
|
+
def _assess_au9(self, bucket_data: Dict) -> str:
|
|
294
|
+
"""
|
|
295
|
+
Assess AU-9 (Protection of Audit Information) compliance.
|
|
296
|
+
|
|
297
|
+
S3 buckets with access logging enabled contribute to AU-9 by protecting audit
|
|
298
|
+
information through AWS's managed infrastructure. Buckets without logging are
|
|
299
|
+
not applicable to this control (N/A is treated as PASS for reporting purposes).
|
|
300
|
+
|
|
301
|
+
:param Dict bucket_data: Bucket configuration data
|
|
302
|
+
:return: Compliance result (always PASS - logging buckets meet requirements, others are N/A)
|
|
303
|
+
:rtype: str
|
|
304
|
+
"""
|
|
305
|
+
logging_config = bucket_data.get("Logging", {})
|
|
306
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
307
|
+
|
|
308
|
+
# Check if this bucket is used for logging
|
|
309
|
+
if logging_config.get("Enabled", False):
|
|
310
|
+
target_bucket = logging_config.get("TargetBucket")
|
|
311
|
+
if target_bucket:
|
|
312
|
+
# Log buckets should have restricted access
|
|
313
|
+
# This is a simplified check - in practice, would need to verify the target bucket config
|
|
314
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES AU-9: Logs stored in {target_bucket}")
|
|
315
|
+
else:
|
|
316
|
+
# If not a logging bucket, this control is N/A but we'll pass it
|
|
317
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES AU-9: Logging configuration appropriate (N/A)")
|
|
318
|
+
|
|
319
|
+
return "PASS"
|
|
320
|
+
|
|
321
|
+
def _assess_cp9(self, bucket_data: Dict) -> str:
|
|
322
|
+
"""
|
|
323
|
+
Assess CP-9 (System Backup) compliance.
|
|
324
|
+
|
|
325
|
+
:param Dict bucket_data: Bucket configuration data
|
|
326
|
+
:return: Compliance result (PASS/FAIL)
|
|
327
|
+
:rtype: str
|
|
328
|
+
"""
|
|
329
|
+
versioning = bucket_data.get("Versioning", {})
|
|
330
|
+
bucket_name = bucket_data.get("Name", "unknown")
|
|
331
|
+
|
|
332
|
+
versioning_status = versioning.get("Status", "Disabled")
|
|
333
|
+
if versioning_status != "Enabled":
|
|
334
|
+
logger.debug(f"S3 bucket {bucket_name} FAILS CP-9: Versioning not enabled for backup")
|
|
335
|
+
return "FAIL"
|
|
336
|
+
|
|
337
|
+
logger.debug(f"S3 bucket {bucket_name} PASSES CP-9: Versioning enabled for data protection")
|
|
338
|
+
return "PASS"
|
|
339
|
+
|
|
340
|
+
def get_control_description(self, control_id: str) -> Optional[str]:
|
|
341
|
+
"""Get human-readable description for a control."""
|
|
342
|
+
control_data = self.mappings.get(control_id)
|
|
343
|
+
if control_data:
|
|
344
|
+
return f"{control_data.get('name')}: {control_data.get('description', '')}"
|
|
345
|
+
return None
|
|
346
|
+
|
|
347
|
+
def get_mapped_controls(self) -> List[str]:
|
|
348
|
+
"""Get list of all control IDs mapped for this framework."""
|
|
349
|
+
return list(self.mappings.keys())
|
|
350
|
+
|
|
351
|
+
def get_check_details(self, control_id: str) -> Optional[Dict]:
|
|
352
|
+
"""Get detailed check criteria for a control."""
|
|
353
|
+
control_data = self.mappings.get(control_id)
|
|
354
|
+
if control_data:
|
|
355
|
+
return control_data.get("checks", {})
|
|
356
|
+
return None
|