aws-cis-controls-assessment 1.0.3__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.
- aws_cis_assessment/__init__.py +11 -0
- aws_cis_assessment/cli/__init__.py +3 -0
- aws_cis_assessment/cli/examples.py +274 -0
- aws_cis_assessment/cli/main.py +1259 -0
- aws_cis_assessment/cli/utils.py +356 -0
- aws_cis_assessment/config/__init__.py +1 -0
- aws_cis_assessment/config/config_loader.py +328 -0
- aws_cis_assessment/config/rules/cis_controls_ig1.yaml +590 -0
- aws_cis_assessment/config/rules/cis_controls_ig2.yaml +412 -0
- aws_cis_assessment/config/rules/cis_controls_ig3.yaml +100 -0
- aws_cis_assessment/controls/__init__.py +1 -0
- aws_cis_assessment/controls/base_control.py +400 -0
- aws_cis_assessment/controls/ig1/__init__.py +239 -0
- aws_cis_assessment/controls/ig1/control_1_1.py +586 -0
- aws_cis_assessment/controls/ig1/control_2_2.py +231 -0
- aws_cis_assessment/controls/ig1/control_3_3.py +718 -0
- aws_cis_assessment/controls/ig1/control_3_4.py +235 -0
- aws_cis_assessment/controls/ig1/control_4_1.py +461 -0
- aws_cis_assessment/controls/ig1/control_access_keys.py +310 -0
- aws_cis_assessment/controls/ig1/control_advanced_security.py +512 -0
- aws_cis_assessment/controls/ig1/control_backup_recovery.py +510 -0
- aws_cis_assessment/controls/ig1/control_cloudtrail_logging.py +197 -0
- aws_cis_assessment/controls/ig1/control_critical_security.py +422 -0
- aws_cis_assessment/controls/ig1/control_data_protection.py +898 -0
- aws_cis_assessment/controls/ig1/control_iam_advanced.py +573 -0
- aws_cis_assessment/controls/ig1/control_iam_governance.py +493 -0
- aws_cis_assessment/controls/ig1/control_iam_policies.py +383 -0
- aws_cis_assessment/controls/ig1/control_instance_optimization.py +100 -0
- aws_cis_assessment/controls/ig1/control_network_enhancements.py +203 -0
- aws_cis_assessment/controls/ig1/control_network_security.py +672 -0
- aws_cis_assessment/controls/ig1/control_s3_enhancements.py +173 -0
- aws_cis_assessment/controls/ig1/control_s3_security.py +422 -0
- aws_cis_assessment/controls/ig1/control_vpc_security.py +235 -0
- aws_cis_assessment/controls/ig2/__init__.py +172 -0
- aws_cis_assessment/controls/ig2/control_3_10.py +698 -0
- aws_cis_assessment/controls/ig2/control_3_11.py +1330 -0
- aws_cis_assessment/controls/ig2/control_5_2.py +393 -0
- aws_cis_assessment/controls/ig2/control_advanced_encryption.py +355 -0
- aws_cis_assessment/controls/ig2/control_codebuild_security.py +263 -0
- aws_cis_assessment/controls/ig2/control_encryption_rest.py +382 -0
- aws_cis_assessment/controls/ig2/control_encryption_transit.py +382 -0
- aws_cis_assessment/controls/ig2/control_network_ha.py +467 -0
- aws_cis_assessment/controls/ig2/control_remaining_encryption.py +426 -0
- aws_cis_assessment/controls/ig2/control_remaining_rules.py +363 -0
- aws_cis_assessment/controls/ig2/control_service_logging.py +402 -0
- aws_cis_assessment/controls/ig3/__init__.py +49 -0
- aws_cis_assessment/controls/ig3/control_12_8.py +395 -0
- aws_cis_assessment/controls/ig3/control_13_1.py +467 -0
- aws_cis_assessment/controls/ig3/control_3_14.py +523 -0
- aws_cis_assessment/controls/ig3/control_7_1.py +359 -0
- aws_cis_assessment/core/__init__.py +1 -0
- aws_cis_assessment/core/accuracy_validator.py +425 -0
- aws_cis_assessment/core/assessment_engine.py +1266 -0
- aws_cis_assessment/core/audit_trail.py +491 -0
- aws_cis_assessment/core/aws_client_factory.py +313 -0
- aws_cis_assessment/core/error_handler.py +607 -0
- aws_cis_assessment/core/models.py +166 -0
- aws_cis_assessment/core/scoring_engine.py +459 -0
- aws_cis_assessment/reporters/__init__.py +8 -0
- aws_cis_assessment/reporters/base_reporter.py +454 -0
- aws_cis_assessment/reporters/csv_reporter.py +835 -0
- aws_cis_assessment/reporters/html_reporter.py +2162 -0
- aws_cis_assessment/reporters/json_reporter.py +561 -0
- aws_cis_controls_assessment-1.0.3.dist-info/METADATA +248 -0
- aws_cis_controls_assessment-1.0.3.dist-info/RECORD +77 -0
- aws_cis_controls_assessment-1.0.3.dist-info/WHEEL +5 -0
- aws_cis_controls_assessment-1.0.3.dist-info/entry_points.txt +2 -0
- aws_cis_controls_assessment-1.0.3.dist-info/licenses/LICENSE +21 -0
- aws_cis_controls_assessment-1.0.3.dist-info/top_level.txt +2 -0
- docs/README.md +94 -0
- docs/assessment-logic.md +766 -0
- docs/cli-reference.md +698 -0
- docs/config-rule-mappings.md +393 -0
- docs/developer-guide.md +858 -0
- docs/installation.md +299 -0
- docs/troubleshooting.md +634 -0
- docs/user-guide.md +487 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
"""Base class for AWS Config rule-based CIS Control assessments."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from typing import List, Dict, Any, Optional
|
|
5
|
+
import logging
|
|
6
|
+
from botocore.exceptions import ClientError
|
|
7
|
+
|
|
8
|
+
from aws_cis_assessment.core.models import (
|
|
9
|
+
ComplianceResult, ComplianceStatus, RemediationGuidance, ConfigRule
|
|
10
|
+
)
|
|
11
|
+
from aws_cis_assessment.core.aws_client_factory import AWSClientFactory
|
|
12
|
+
from aws_cis_assessment.core.error_handler import ErrorHandler, ErrorContext, ErrorCategory
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class BaseConfigRuleAssessment(ABC):
|
|
18
|
+
"""Abstract base class for all AWS Config rule implementations."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, rule_name: str, control_id: str, resource_types: List[str],
|
|
21
|
+
parameters: Optional[Dict[str, Any]] = None,
|
|
22
|
+
error_handler: Optional[ErrorHandler] = None):
|
|
23
|
+
"""Initialize Config rule assessment with rule specification.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
rule_name: AWS Config rule name
|
|
27
|
+
control_id: CIS Control ID (e.g., "1.1", "3.3")
|
|
28
|
+
resource_types: List of AWS resource types to evaluate
|
|
29
|
+
parameters: Optional parameters for rule evaluation
|
|
30
|
+
error_handler: Optional error handler for graceful degradation
|
|
31
|
+
"""
|
|
32
|
+
self.rule_name = rule_name
|
|
33
|
+
self.control_id = control_id
|
|
34
|
+
self.resource_types = resource_types
|
|
35
|
+
self.parameters = parameters or {}
|
|
36
|
+
self.error_handler = error_handler
|
|
37
|
+
|
|
38
|
+
# Validate inputs
|
|
39
|
+
if not rule_name:
|
|
40
|
+
raise ValueError("Rule name cannot be empty")
|
|
41
|
+
if not control_id:
|
|
42
|
+
raise ValueError("Control ID cannot be empty")
|
|
43
|
+
if not resource_types:
|
|
44
|
+
raise ValueError("Must specify at least one resource type")
|
|
45
|
+
|
|
46
|
+
def evaluate_compliance(self, aws_factory: AWSClientFactory, region: str = 'us-east-1') -> List[ComplianceResult]:
|
|
47
|
+
"""Evaluate compliance for all applicable resources.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
aws_factory: AWS client factory for API access
|
|
51
|
+
region: AWS region to evaluate
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
List of ComplianceResult objects for all evaluated resources
|
|
55
|
+
"""
|
|
56
|
+
results = []
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
# Validate that we can access required services
|
|
60
|
+
if not self._validate_service_access(aws_factory, region):
|
|
61
|
+
return [self._create_error_result(
|
|
62
|
+
"SERVICE_UNAVAILABLE",
|
|
63
|
+
f"Required AWS services not accessible in region {region}",
|
|
64
|
+
region
|
|
65
|
+
)]
|
|
66
|
+
|
|
67
|
+
# Evaluate each resource type
|
|
68
|
+
for resource_type in self.resource_types:
|
|
69
|
+
try:
|
|
70
|
+
# Use error handler for resource discovery if available
|
|
71
|
+
def get_resources():
|
|
72
|
+
return self._get_resources(aws_factory, resource_type, region)
|
|
73
|
+
|
|
74
|
+
if self.error_handler:
|
|
75
|
+
context = ErrorContext(
|
|
76
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
77
|
+
region=region,
|
|
78
|
+
resource_type=resource_type,
|
|
79
|
+
operation="get_resources",
|
|
80
|
+
control_id=self.control_id,
|
|
81
|
+
config_rule_name=self.rule_name
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
resources = self.error_handler.handle_error(
|
|
85
|
+
Exception("Resource discovery"), context, get_resources
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if resources is None:
|
|
89
|
+
resources = get_resources()
|
|
90
|
+
else:
|
|
91
|
+
resources = get_resources()
|
|
92
|
+
|
|
93
|
+
logger.debug(f"Found {len(resources)} resources of type {resource_type} in {region}")
|
|
94
|
+
|
|
95
|
+
for resource in resources:
|
|
96
|
+
try:
|
|
97
|
+
# Use error handler for resource evaluation if available
|
|
98
|
+
def evaluate_resource():
|
|
99
|
+
return self._evaluate_resource_compliance(resource, aws_factory, region)
|
|
100
|
+
|
|
101
|
+
if self.error_handler:
|
|
102
|
+
context = ErrorContext(
|
|
103
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
104
|
+
region=region,
|
|
105
|
+
resource_type=resource_type,
|
|
106
|
+
resource_id=resource.get('id', 'unknown'),
|
|
107
|
+
operation="evaluate_compliance",
|
|
108
|
+
control_id=self.control_id,
|
|
109
|
+
config_rule_name=self.rule_name
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
compliance = self.error_handler.handle_error(
|
|
113
|
+
Exception("Resource evaluation"), context, evaluate_resource
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if compliance is None:
|
|
117
|
+
compliance = evaluate_resource()
|
|
118
|
+
else:
|
|
119
|
+
compliance = evaluate_resource()
|
|
120
|
+
|
|
121
|
+
results.append(compliance)
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Error evaluating resource {resource.get('id', 'unknown')}: {e}")
|
|
125
|
+
|
|
126
|
+
# Handle error with error handler if available
|
|
127
|
+
if self.error_handler:
|
|
128
|
+
context = ErrorContext(
|
|
129
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
130
|
+
region=region,
|
|
131
|
+
resource_type=resource_type,
|
|
132
|
+
resource_id=resource.get('id', 'unknown'),
|
|
133
|
+
operation="evaluate_compliance",
|
|
134
|
+
control_id=self.control_id,
|
|
135
|
+
config_rule_name=self.rule_name
|
|
136
|
+
)
|
|
137
|
+
self.error_handler.handle_error(e, context)
|
|
138
|
+
|
|
139
|
+
results.append(self._create_error_result(
|
|
140
|
+
resource.get('id', 'unknown'),
|
|
141
|
+
f"Evaluation error: {str(e)}",
|
|
142
|
+
region,
|
|
143
|
+
resource_type
|
|
144
|
+
))
|
|
145
|
+
|
|
146
|
+
except ClientError as e:
|
|
147
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
148
|
+
error_message = f"AWS API error: {str(e)}"
|
|
149
|
+
|
|
150
|
+
# Handle error with error handler if available
|
|
151
|
+
if self.error_handler:
|
|
152
|
+
context = ErrorContext(
|
|
153
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
154
|
+
region=region,
|
|
155
|
+
resource_type=resource_type,
|
|
156
|
+
operation="get_resources",
|
|
157
|
+
control_id=self.control_id,
|
|
158
|
+
config_rule_name=self.rule_name
|
|
159
|
+
)
|
|
160
|
+
self.error_handler.handle_error(e, context)
|
|
161
|
+
|
|
162
|
+
if error_code in ['AccessDenied', 'UnauthorizedOperation']:
|
|
163
|
+
results.append(self._create_error_result(
|
|
164
|
+
f"{resource_type}_PERMISSION_ERROR",
|
|
165
|
+
f"Insufficient permissions to evaluate {resource_type}",
|
|
166
|
+
region,
|
|
167
|
+
resource_type
|
|
168
|
+
))
|
|
169
|
+
else:
|
|
170
|
+
results.append(self._create_error_result(
|
|
171
|
+
f"{resource_type}_API_ERROR",
|
|
172
|
+
error_message,
|
|
173
|
+
region,
|
|
174
|
+
resource_type
|
|
175
|
+
))
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
logger.error(f"Unexpected error evaluating {resource_type}: {e}")
|
|
179
|
+
|
|
180
|
+
# Handle error with error handler if available
|
|
181
|
+
if self.error_handler:
|
|
182
|
+
context = ErrorContext(
|
|
183
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
184
|
+
region=region,
|
|
185
|
+
resource_type=resource_type,
|
|
186
|
+
operation="evaluate_resource_type",
|
|
187
|
+
control_id=self.control_id,
|
|
188
|
+
config_rule_name=self.rule_name
|
|
189
|
+
)
|
|
190
|
+
self.error_handler.handle_error(e, context)
|
|
191
|
+
|
|
192
|
+
results.append(self._create_error_result(
|
|
193
|
+
f"{resource_type}_UNKNOWN_ERROR",
|
|
194
|
+
f"Unexpected error: {str(e)}",
|
|
195
|
+
region,
|
|
196
|
+
resource_type
|
|
197
|
+
))
|
|
198
|
+
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error(f"Critical error in compliance evaluation: {e}")
|
|
201
|
+
|
|
202
|
+
# Handle critical error with error handler if available
|
|
203
|
+
if self.error_handler:
|
|
204
|
+
context = ErrorContext(
|
|
205
|
+
service_name=self._get_required_services()[0] if self._get_required_services() else "",
|
|
206
|
+
region=region,
|
|
207
|
+
operation="evaluate_compliance",
|
|
208
|
+
control_id=self.control_id,
|
|
209
|
+
config_rule_name=self.rule_name
|
|
210
|
+
)
|
|
211
|
+
self.error_handler.handle_error(e, context)
|
|
212
|
+
|
|
213
|
+
results.append(self._create_error_result(
|
|
214
|
+
"CRITICAL_ERROR",
|
|
215
|
+
f"Critical evaluation error: {str(e)}",
|
|
216
|
+
region
|
|
217
|
+
))
|
|
218
|
+
|
|
219
|
+
return results
|
|
220
|
+
|
|
221
|
+
@abstractmethod
|
|
222
|
+
def _evaluate_resource_compliance(self, resource: Dict[str, Any], aws_factory: AWSClientFactory, region: str) -> ComplianceResult:
|
|
223
|
+
"""Evaluate compliance for individual resource.
|
|
224
|
+
|
|
225
|
+
This method must be implemented by subclasses with specific Config rule logic.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
resource: Resource data dictionary
|
|
229
|
+
aws_factory: AWS client factory for additional API calls
|
|
230
|
+
region: AWS region
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
ComplianceResult for the resource
|
|
234
|
+
"""
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
@abstractmethod
|
|
238
|
+
def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
|
|
239
|
+
"""Discover resources of specified type in region.
|
|
240
|
+
|
|
241
|
+
This method must be implemented by subclasses based on resource type.
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
aws_factory: AWS client factory for API access
|
|
245
|
+
resource_type: AWS resource type (e.g., "AWS::EC2::Instance")
|
|
246
|
+
region: AWS region
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
List of resource dictionaries
|
|
250
|
+
"""
|
|
251
|
+
pass
|
|
252
|
+
|
|
253
|
+
def _validate_service_access(self, aws_factory: AWSClientFactory, region: str) -> bool:
|
|
254
|
+
"""Validate that required AWS services are accessible.
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
aws_factory: AWS client factory
|
|
258
|
+
region: AWS region
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
True if all required services are accessible
|
|
262
|
+
"""
|
|
263
|
+
required_services = self._get_required_services()
|
|
264
|
+
|
|
265
|
+
for service in required_services:
|
|
266
|
+
if not aws_factory.test_service_access(service, region):
|
|
267
|
+
logger.debug(f"Service {service} not accessible in region {region}")
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
return True
|
|
271
|
+
|
|
272
|
+
def _get_required_services(self) -> List[str]:
|
|
273
|
+
"""Get list of AWS services required for this assessment.
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
List of AWS service names
|
|
277
|
+
"""
|
|
278
|
+
# Map resource types to services
|
|
279
|
+
service_mapping = {
|
|
280
|
+
'AWS::EC2::': 'ec2',
|
|
281
|
+
'AWS::IAM::': 'iam',
|
|
282
|
+
'AWS::S3::': 's3',
|
|
283
|
+
'AWS::RDS::': 'rds',
|
|
284
|
+
'AWS::CloudTrail::': 'cloudtrail',
|
|
285
|
+
'AWS::ElasticLoadBalancing::': 'elbv2', # Classic ELB uses elbv2 client in boto3
|
|
286
|
+
'AWS::ElasticLoadBalancingV2::': 'elbv2', # ALB/NLB use elbv2 client
|
|
287
|
+
'AWS::ApiGateway::': 'apigateway',
|
|
288
|
+
'AWS::DynamoDB::': 'dynamodb',
|
|
289
|
+
'AWS::::Account': 'sts' # Special case for account-level resources
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
services = set()
|
|
293
|
+
for resource_type in self.resource_types:
|
|
294
|
+
for prefix, service in service_mapping.items():
|
|
295
|
+
if resource_type.startswith(prefix):
|
|
296
|
+
services.add(service)
|
|
297
|
+
break
|
|
298
|
+
|
|
299
|
+
return list(services)
|
|
300
|
+
|
|
301
|
+
def _create_error_result(self, resource_id: str, error_message: str, region: str, resource_type: str = "Unknown") -> ComplianceResult:
|
|
302
|
+
"""Create a ComplianceResult for error conditions.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
resource_id: Resource identifier
|
|
306
|
+
error_message: Error description
|
|
307
|
+
region: AWS region
|
|
308
|
+
resource_type: AWS resource type
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
ComplianceResult with ERROR status
|
|
312
|
+
"""
|
|
313
|
+
return ComplianceResult(
|
|
314
|
+
resource_id=resource_id,
|
|
315
|
+
resource_type=resource_type,
|
|
316
|
+
compliance_status=ComplianceStatus.ERROR,
|
|
317
|
+
evaluation_reason=error_message,
|
|
318
|
+
config_rule_name=self.rule_name,
|
|
319
|
+
region=region
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
def get_remediation_guidance(self, non_compliant_resources: List[ComplianceResult]) -> RemediationGuidance:
|
|
323
|
+
"""Provide remediation guidance based on AWS Config rule documentation.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
non_compliant_resources: List of non-compliant resources
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
RemediationGuidance object with specific steps
|
|
330
|
+
"""
|
|
331
|
+
return RemediationGuidance(
|
|
332
|
+
config_rule_name=self.rule_name,
|
|
333
|
+
control_id=self.control_id,
|
|
334
|
+
remediation_steps=self._get_rule_remediation_steps(),
|
|
335
|
+
aws_documentation_link=f"https://docs.aws.amazon.com/config/latest/developerguide/{self.rule_name}.html",
|
|
336
|
+
priority=self._determine_priority(non_compliant_resources),
|
|
337
|
+
estimated_effort=self._estimate_remediation_effort(non_compliant_resources)
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
def _get_rule_remediation_steps(self) -> List[str]:
|
|
341
|
+
"""Get remediation steps for this Config rule.
|
|
342
|
+
|
|
343
|
+
Override in subclasses for rule-specific guidance.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
List of remediation step descriptions
|
|
347
|
+
"""
|
|
348
|
+
return [
|
|
349
|
+
f"Review non-compliant resources identified by {self.rule_name}",
|
|
350
|
+
f"Apply remediation actions according to CIS Control {self.control_id}",
|
|
351
|
+
"Verify compliance after remediation",
|
|
352
|
+
"Monitor for future compliance drift"
|
|
353
|
+
]
|
|
354
|
+
|
|
355
|
+
def _determine_priority(self, non_compliant_resources: List[ComplianceResult]) -> str:
|
|
356
|
+
"""Determine remediation priority based on non-compliant resources.
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
non_compliant_resources: List of non-compliant resources
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
Priority level: HIGH, MEDIUM, or LOW
|
|
363
|
+
"""
|
|
364
|
+
if not non_compliant_resources:
|
|
365
|
+
return "LOW"
|
|
366
|
+
|
|
367
|
+
# High priority for security-critical controls
|
|
368
|
+
high_priority_controls = ["3.3", "5.2", "6.4", "8.1"]
|
|
369
|
+
if self.control_id in high_priority_controls:
|
|
370
|
+
return "HIGH"
|
|
371
|
+
|
|
372
|
+
# Medium priority for most controls
|
|
373
|
+
if len(non_compliant_resources) > 5:
|
|
374
|
+
return "HIGH"
|
|
375
|
+
elif len(non_compliant_resources) > 1:
|
|
376
|
+
return "MEDIUM"
|
|
377
|
+
else:
|
|
378
|
+
return "LOW"
|
|
379
|
+
|
|
380
|
+
def _estimate_remediation_effort(self, non_compliant_resources: List[ComplianceResult]) -> str:
|
|
381
|
+
"""Estimate effort required for remediation.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
non_compliant_resources: List of non-compliant resources
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
Effort estimate: Low, Medium, High, or Very High
|
|
388
|
+
"""
|
|
389
|
+
resource_count = len(non_compliant_resources)
|
|
390
|
+
|
|
391
|
+
if resource_count == 0:
|
|
392
|
+
return "None"
|
|
393
|
+
elif resource_count <= 5:
|
|
394
|
+
return "Low"
|
|
395
|
+
elif resource_count <= 20:
|
|
396
|
+
return "Medium"
|
|
397
|
+
elif resource_count <= 50:
|
|
398
|
+
return "High"
|
|
399
|
+
else:
|
|
400
|
+
return "Very High"
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""IG1 Essential Cyber Hygiene Control implementations."""
|
|
2
|
+
|
|
3
|
+
from .control_1_1 import (
|
|
4
|
+
EIPAttachedAssessment,
|
|
5
|
+
EC2StoppedInstanceAssessment,
|
|
6
|
+
VPCNetworkACLUnusedAssessment,
|
|
7
|
+
EC2InstanceManagedBySSMAssessment,
|
|
8
|
+
EC2SecurityGroupAttachedAssessment
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
from .control_2_2 import (
|
|
12
|
+
ElasticBeanstalkManagedUpdatesEnabledAssessment,
|
|
13
|
+
ECSFargateLatestPlatformVersionAssessment
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .control_3_3 import (
|
|
17
|
+
IAMPasswordPolicyAssessment,
|
|
18
|
+
IAMUserMFAEnabledAssessment,
|
|
19
|
+
IAMRootAccessKeyAssessment,
|
|
20
|
+
S3BucketPublicReadProhibitedAssessment,
|
|
21
|
+
EC2InstanceNoPublicIPAssessment
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from .control_3_4 import (
|
|
25
|
+
S3VersionLifecyclePolicyAssessment,
|
|
26
|
+
CloudWatchLogGroupRetentionAssessment
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from .control_4_1 import (
|
|
30
|
+
AccountPartOfOrganizationsAssessment,
|
|
31
|
+
EC2VolumeInUseAssessment,
|
|
32
|
+
RedshiftClusterMaintenanceSettingsAssessment,
|
|
33
|
+
SecretsManagerRotationEnabledAssessment
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
from .control_access_keys import (
|
|
37
|
+
AccessKeysRotatedAssessment,
|
|
38
|
+
EC2IMDSv2CheckAssessment,
|
|
39
|
+
EC2InstanceProfileAttachedAssessment
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
from .control_iam_policies import (
|
|
43
|
+
IAMPolicyNoStatementsWithAdminAccessAssessment,
|
|
44
|
+
IAMNoInlinePolicyCheckAssessment,
|
|
45
|
+
IAMUserGroupMembershipCheckAssessment
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
from .control_s3_security import (
|
|
49
|
+
S3BucketSSLRequestsOnlyAssessment,
|
|
50
|
+
S3BucketServerSideEncryptionEnabledAssessment,
|
|
51
|
+
S3BucketLoggingEnabledAssessment,
|
|
52
|
+
S3BucketVersioningEnabledAssessment
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
from .control_data_protection import (
|
|
56
|
+
EBSSnapshotPublicRestorableCheckAssessment,
|
|
57
|
+
RDSSnapshotsPublicProhibitedAssessment,
|
|
58
|
+
RDSInstancePublicAccessCheckAssessment,
|
|
59
|
+
RedshiftClusterPublicAccessCheckAssessment,
|
|
60
|
+
S3BucketLevelPublicAccessProhibitedAssessment
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
from .control_network_security import (
|
|
64
|
+
DMSReplicationNotPublicAssessment,
|
|
65
|
+
ElasticsearchInVPCOnlyAssessment,
|
|
66
|
+
EC2InstancesInVPCAssessment,
|
|
67
|
+
EMRMasterNoPublicIPAssessment,
|
|
68
|
+
LambdaFunctionPublicAccessProhibitedAssessment,
|
|
69
|
+
SageMakerNotebookNoDirectInternetAccessAssessment,
|
|
70
|
+
SubnetAutoAssignPublicIPDisabledAssessment
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
from .control_iam_governance import (
|
|
74
|
+
IAMGroupHasUsersCheckAssessment,
|
|
75
|
+
IAMPolicyNoStatementsWithFullAccessAssessment,
|
|
76
|
+
IAMUserNoPoliciesCheckAssessment,
|
|
77
|
+
SSMDocumentNotPublicAssessment
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
from .control_advanced_security import (
|
|
81
|
+
EC2ManagedInstanceAssociationComplianceStatusCheckAssessment,
|
|
82
|
+
EMRKerberosEnabledAssessment,
|
|
83
|
+
LambdaInsideVPCAssessment,
|
|
84
|
+
ECSTaskDefinitionUserForHostModeCheckAssessment
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
from .control_iam_advanced import (
|
|
88
|
+
IAMRootAccessKeyCheckAssessment,
|
|
89
|
+
IAMUserUnusedCredentialsCheckAssessment,
|
|
90
|
+
IAMCustomerPolicyBlockedKMSActionsAssessment,
|
|
91
|
+
IAMInlinePolicyBlockedKMSActionsAssessment
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
from .control_cloudtrail_logging import (
|
|
95
|
+
CloudTrailEnabledAssessment,
|
|
96
|
+
CloudWatchLogGroupEncryptedAssessment
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
from .control_vpc_security import (
|
|
100
|
+
VPCDefaultSecurityGroupClosedAssessment,
|
|
101
|
+
RestrictedSSHAssessment
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
from .control_critical_security import (
|
|
105
|
+
RootAccountHardwareMFAEnabledAssessment,
|
|
106
|
+
OpenSearchInVPCOnlyAssessment,
|
|
107
|
+
ECSTaskDefinitionNonRootUserAssessment,
|
|
108
|
+
SecurityHubEnabledAssessment
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
from .control_network_enhancements import (
|
|
112
|
+
ElasticsearchNodeToNodeEncryptionCheckAssessment,
|
|
113
|
+
AutoScalingLaunchConfigPublicIPDisabledAssessment,
|
|
114
|
+
EFSAccessPointEnforceRootDirectoryAssessment
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
from .control_backup_recovery import (
|
|
118
|
+
DynamoDBInBackupPlanAssessment,
|
|
119
|
+
EBSInBackupPlanAssessment,
|
|
120
|
+
EFSInBackupPlanAssessment,
|
|
121
|
+
DBInstanceBackupEnabledAssessment,
|
|
122
|
+
RedshiftBackupEnabledAssessment,
|
|
123
|
+
DynamoDBPITREnabledAssessment,
|
|
124
|
+
ElastiCacheRedisClusterAutomaticBackupCheckAssessment,
|
|
125
|
+
S3BucketReplicationEnabledAssessment
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
from .control_s3_enhancements import (
|
|
129
|
+
S3AccountLevelPublicAccessBlocksPeriodicAssessment,
|
|
130
|
+
S3BucketPublicWriteProhibitedAssessment
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
from .control_instance_optimization import (
|
|
134
|
+
EBSOptimizedInstanceAssessment
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
__all__ = [
|
|
138
|
+
# Control 1.1 - Asset Inventory
|
|
139
|
+
'EIPAttachedAssessment',
|
|
140
|
+
'EC2StoppedInstanceAssessment',
|
|
141
|
+
'VPCNetworkACLUnusedAssessment',
|
|
142
|
+
'EC2InstanceManagedBySSMAssessment',
|
|
143
|
+
'EC2SecurityGroupAttachedAssessment',
|
|
144
|
+
|
|
145
|
+
# Control 2.2 - Authorized Software Support
|
|
146
|
+
'ElasticBeanstalkManagedUpdatesEnabledAssessment',
|
|
147
|
+
'ECSFargateLatestPlatformVersionAssessment',
|
|
148
|
+
|
|
149
|
+
# Control 3.3 - Data Access Control
|
|
150
|
+
'IAMPasswordPolicyAssessment',
|
|
151
|
+
'IAMUserMFAEnabledAssessment',
|
|
152
|
+
'IAMRootAccessKeyAssessment',
|
|
153
|
+
'S3BucketPublicReadProhibitedAssessment',
|
|
154
|
+
'EC2InstanceNoPublicIPAssessment',
|
|
155
|
+
'EC2IMDSv2CheckAssessment',
|
|
156
|
+
'EC2InstanceProfileAttachedAssessment',
|
|
157
|
+
'IAMPolicyNoStatementsWithAdminAccessAssessment',
|
|
158
|
+
'IAMNoInlinePolicyCheckAssessment',
|
|
159
|
+
'IAMUserGroupMembershipCheckAssessment',
|
|
160
|
+
'EBSSnapshotPublicRestorableCheckAssessment',
|
|
161
|
+
'RDSSnapshotsPublicProhibitedAssessment',
|
|
162
|
+
'RDSInstancePublicAccessCheckAssessment',
|
|
163
|
+
'RedshiftClusterPublicAccessCheckAssessment',
|
|
164
|
+
'S3BucketLevelPublicAccessProhibitedAssessment',
|
|
165
|
+
'DMSReplicationNotPublicAssessment',
|
|
166
|
+
'ElasticsearchInVPCOnlyAssessment',
|
|
167
|
+
'EC2InstancesInVPCAssessment',
|
|
168
|
+
'EMRMasterNoPublicIPAssessment',
|
|
169
|
+
'LambdaFunctionPublicAccessProhibitedAssessment',
|
|
170
|
+
'SageMakerNotebookNoDirectInternetAccessAssessment',
|
|
171
|
+
'SubnetAutoAssignPublicIPDisabledAssessment',
|
|
172
|
+
'IAMGroupHasUsersCheckAssessment',
|
|
173
|
+
'IAMPolicyNoStatementsWithFullAccessAssessment',
|
|
174
|
+
'IAMUserNoPoliciesCheckAssessment',
|
|
175
|
+
'SSMDocumentNotPublicAssessment',
|
|
176
|
+
'EC2ManagedInstanceAssociationComplianceStatusCheckAssessment',
|
|
177
|
+
'EMRKerberosEnabledAssessment',
|
|
178
|
+
'LambdaInsideVPCAssessment',
|
|
179
|
+
'ECSTaskDefinitionUserForHostModeCheckAssessment',
|
|
180
|
+
'IAMRootAccessKeyCheckAssessment',
|
|
181
|
+
'IAMUserUnusedCredentialsCheckAssessment',
|
|
182
|
+
'IAMCustomerPolicyBlockedKMSActionsAssessment',
|
|
183
|
+
'IAMInlinePolicyBlockedKMSActionsAssessment',
|
|
184
|
+
|
|
185
|
+
# Control 3.4 - Data Retention
|
|
186
|
+
'S3VersionLifecyclePolicyAssessment',
|
|
187
|
+
'CloudWatchLogGroupRetentionAssessment',
|
|
188
|
+
|
|
189
|
+
# Control 4.1 - Secure Configuration Process
|
|
190
|
+
'AccountPartOfOrganizationsAssessment',
|
|
191
|
+
'EC2VolumeInUseAssessment',
|
|
192
|
+
'RedshiftClusterMaintenanceSettingsAssessment',
|
|
193
|
+
'SecretsManagerRotationEnabledAssessment',
|
|
194
|
+
'AccessKeysRotatedAssessment',
|
|
195
|
+
|
|
196
|
+
# Control 11.2 - Backup Management
|
|
197
|
+
'S3BucketVersioningEnabledAssessment',
|
|
198
|
+
|
|
199
|
+
# S3 Security Controls (Phase 5)
|
|
200
|
+
'S3BucketSSLRequestsOnlyAssessment',
|
|
201
|
+
'S3BucketServerSideEncryptionEnabledAssessment',
|
|
202
|
+
'S3BucketLoggingEnabledAssessment',
|
|
203
|
+
|
|
204
|
+
# CloudTrail & Logging Controls (Phase 6)
|
|
205
|
+
'CloudTrailEnabledAssessment',
|
|
206
|
+
'CloudWatchLogGroupEncryptedAssessment',
|
|
207
|
+
|
|
208
|
+
# VPC Security Controls (Phase 6)
|
|
209
|
+
'VPCDefaultSecurityGroupClosedAssessment',
|
|
210
|
+
'RestrictedSSHAssessment',
|
|
211
|
+
|
|
212
|
+
# Critical Security Controls
|
|
213
|
+
'RootAccountHardwareMFAEnabledAssessment',
|
|
214
|
+
'OpenSearchInVPCOnlyAssessment',
|
|
215
|
+
'ECSTaskDefinitionNonRootUserAssessment',
|
|
216
|
+
'SecurityHubEnabledAssessment',
|
|
217
|
+
|
|
218
|
+
# Network Security Enhancements
|
|
219
|
+
'ElasticsearchNodeToNodeEncryptionCheckAssessment',
|
|
220
|
+
'AutoScalingLaunchConfigPublicIPDisabledAssessment',
|
|
221
|
+
'EFSAccessPointEnforceRootDirectoryAssessment',
|
|
222
|
+
|
|
223
|
+
# Backup & Recovery Controls
|
|
224
|
+
'DynamoDBInBackupPlanAssessment',
|
|
225
|
+
'EBSInBackupPlanAssessment',
|
|
226
|
+
'EFSInBackupPlanAssessment',
|
|
227
|
+
'DBInstanceBackupEnabledAssessment',
|
|
228
|
+
'RedshiftBackupEnabledAssessment',
|
|
229
|
+
'DynamoDBPITREnabledAssessment',
|
|
230
|
+
'ElastiCacheRedisClusterAutomaticBackupCheckAssessment',
|
|
231
|
+
'S3BucketReplicationEnabledAssessment',
|
|
232
|
+
|
|
233
|
+
# S3 Security Enhancements
|
|
234
|
+
'S3AccountLevelPublicAccessBlocksPeriodicAssessment',
|
|
235
|
+
'S3BucketPublicWriteProhibitedAssessment',
|
|
236
|
+
|
|
237
|
+
# Instance Optimization
|
|
238
|
+
'EBSOptimizedInstanceAssessment'
|
|
239
|
+
]
|