aws-cis-controls-assessment 1.1.4__py3-none-any.whl → 1.2.2__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 +4 -4
- aws_cis_assessment/config/rules/cis_controls_ig1.yaml +365 -2
- aws_cis_assessment/controls/base_control.py +106 -24
- aws_cis_assessment/controls/ig1/__init__.py +144 -15
- aws_cis_assessment/controls/ig1/control_4_1.py +4 -4
- aws_cis_assessment/controls/ig1/control_access_analyzer.py +198 -0
- aws_cis_assessment/controls/ig1/control_access_asset_mgmt.py +360 -0
- aws_cis_assessment/controls/ig1/control_access_control.py +323 -0
- aws_cis_assessment/controls/ig1/control_backup_security.py +579 -0
- aws_cis_assessment/controls/ig1/control_cloudfront_logging.py +215 -0
- aws_cis_assessment/controls/ig1/control_configuration_mgmt.py +407 -0
- aws_cis_assessment/controls/ig1/control_data_classification.py +255 -0
- aws_cis_assessment/controls/ig1/control_dynamodb_encryption.py +279 -0
- aws_cis_assessment/controls/ig1/control_ebs_encryption.py +177 -0
- aws_cis_assessment/controls/ig1/control_efs_encryption.py +243 -0
- aws_cis_assessment/controls/ig1/control_elb_logging.py +195 -0
- aws_cis_assessment/controls/ig1/control_guardduty.py +156 -0
- aws_cis_assessment/controls/ig1/control_inspector.py +184 -0
- aws_cis_assessment/controls/ig1/control_inventory.py +511 -0
- aws_cis_assessment/controls/ig1/control_macie.py +165 -0
- aws_cis_assessment/controls/ig1/control_messaging_encryption.py +419 -0
- aws_cis_assessment/controls/ig1/control_mfa.py +485 -0
- aws_cis_assessment/controls/ig1/control_network_security.py +194 -619
- aws_cis_assessment/controls/ig1/control_patch_management.py +626 -0
- aws_cis_assessment/controls/ig1/control_rds_encryption.py +228 -0
- aws_cis_assessment/controls/ig1/control_s3_encryption.py +383 -0
- aws_cis_assessment/controls/ig1/control_tls_ssl.py +556 -0
- aws_cis_assessment/controls/ig1/control_version_mgmt.py +337 -0
- aws_cis_assessment/controls/ig1/control_vpc_flow_logs.py +205 -0
- aws_cis_assessment/controls/ig1/control_waf_logging.py +226 -0
- aws_cis_assessment/core/assessment_engine.py +160 -11
- aws_cis_assessment/core/aws_client_factory.py +17 -5
- aws_cis_assessment/core/models.py +20 -1
- aws_cis_assessment/core/scoring_engine.py +102 -1
- aws_cis_assessment/reporters/base_reporter.py +58 -13
- aws_cis_assessment/reporters/html_reporter.py +186 -9
- aws_cis_controls_assessment-1.2.2.dist-info/METADATA +320 -0
- {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/RECORD +44 -20
- docs/developer-guide.md +204 -5
- docs/user-guide.md +137 -4
- aws_cis_controls_assessment-1.1.4.dist-info/METADATA +0 -404
- {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/WHEEL +0 -0
- {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/entry_points.txt +0 -0
- {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/licenses/LICENSE +0 -0
- {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/top_level.txt +0 -0
|
@@ -61,13 +61,8 @@ from .control_data_protection import (
|
|
|
61
61
|
)
|
|
62
62
|
|
|
63
63
|
from .control_network_security import (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
EC2InstancesInVPCAssessment,
|
|
67
|
-
EMRMasterNoPublicIPAssessment,
|
|
68
|
-
LambdaFunctionPublicAccessProhibitedAssessment,
|
|
69
|
-
SageMakerNotebookNoDirectInternetAccessAssessment,
|
|
70
|
-
SubnetAutoAssignPublicIPDisabledAssessment
|
|
64
|
+
NetworkFirewallDeployedAssessment,
|
|
65
|
+
Route53ResolverFirewallEnabledAssessment
|
|
71
66
|
)
|
|
72
67
|
|
|
73
68
|
from .control_iam_governance import (
|
|
@@ -143,6 +138,85 @@ from .control_instance_optimization import (
|
|
|
143
138
|
EBSOptimizedInstanceAssessment
|
|
144
139
|
)
|
|
145
140
|
|
|
141
|
+
# Phase 1-4: CIS Controls v8.1 IG1 Expansion
|
|
142
|
+
from .control_guardduty import GuardDutyEnabledAssessment
|
|
143
|
+
from .control_inspector import InspectorEnabledAssessment
|
|
144
|
+
from .control_macie import MacieEnabledAssessment
|
|
145
|
+
from .control_access_analyzer import IAMAccessAnalyzerEnabledAssessment
|
|
146
|
+
from .control_vpc_flow_logs import VPCFlowLogsEnabledAssessment
|
|
147
|
+
from .control_elb_logging import ELBLoggingEnabledAssessment
|
|
148
|
+
from .control_cloudfront_logging import CloudFrontLoggingEnabledAssessment
|
|
149
|
+
from .control_waf_logging import WAFLoggingEnabledAssessment
|
|
150
|
+
from .control_ebs_encryption import EBSEncryptionByDefaultAssessment
|
|
151
|
+
from .control_rds_encryption import RDSStorageEncryptedAssessment
|
|
152
|
+
from .control_efs_encryption import EFSEncryptedCheckAssessment
|
|
153
|
+
from .control_dynamodb_encryption import DynamoDBTableEncryptedKMSAssessment
|
|
154
|
+
from .control_s3_encryption import S3DefaultEncryptionKMSAssessment
|
|
155
|
+
from .control_patch_management import (
|
|
156
|
+
SSMPatchManagerEnabledAssessment,
|
|
157
|
+
SSMPatchBaselineConfiguredAssessment,
|
|
158
|
+
EC2PatchComplianceStatusAssessment
|
|
159
|
+
)
|
|
160
|
+
from .control_access_control import (
|
|
161
|
+
SSOEnabledCheckAssessment,
|
|
162
|
+
IdentityCenterConfiguredAssessment
|
|
163
|
+
)
|
|
164
|
+
from .control_mfa import (
|
|
165
|
+
IAMAdminMFARequiredAssessment,
|
|
166
|
+
CognitoMFAEnabledAssessment,
|
|
167
|
+
VPNMFAEnabledAssessment
|
|
168
|
+
)
|
|
169
|
+
from .control_tls_ssl import (
|
|
170
|
+
ALBHTTPToHTTPSRedirectionAssessment,
|
|
171
|
+
ELBTLSHTTPSListenersOnlyAssessment,
|
|
172
|
+
RDSSSLConnectionRequiredAssessment,
|
|
173
|
+
APIGatewaySSLEnabledAssessment,
|
|
174
|
+
RedshiftRequireTLSSSLAssessment
|
|
175
|
+
)
|
|
176
|
+
from .control_messaging_encryption import (
|
|
177
|
+
SNSEncryptedKMSAssessment,
|
|
178
|
+
SQSQueueEncryptedAssessment,
|
|
179
|
+
CloudTrailS3DataEventsEnabledAssessment
|
|
180
|
+
)
|
|
181
|
+
from .control_inventory import (
|
|
182
|
+
SSMInventoryEnabledAssessment,
|
|
183
|
+
ConfigEnabledAllRegionsAssessment,
|
|
184
|
+
AMIInventoryTrackingAssessment,
|
|
185
|
+
LambdaRuntimeInventoryAssessment,
|
|
186
|
+
IAMUserInventoryCheckAssessment
|
|
187
|
+
)
|
|
188
|
+
from .control_configuration_mgmt import (
|
|
189
|
+
ConfigConformancePackDeployedAssessment,
|
|
190
|
+
SecurityHubStandardsEnabledAssessment,
|
|
191
|
+
AssetTaggingComplianceAssessment,
|
|
192
|
+
InspectorAssessmentEnabledAssessment
|
|
193
|
+
)
|
|
194
|
+
from .control_version_mgmt import (
|
|
195
|
+
EC2OSVersionSupportedAssessment,
|
|
196
|
+
RDSEngineVersionSupportedAssessment,
|
|
197
|
+
LambdaRuntimeSupportedAssessment
|
|
198
|
+
)
|
|
199
|
+
from .control_access_asset_mgmt import (
|
|
200
|
+
IAMUserLastAccessCheckAssessment,
|
|
201
|
+
SSMSessionManagerEnabledAssessment,
|
|
202
|
+
UnauthorizedAssetDetectionAssessment
|
|
203
|
+
)
|
|
204
|
+
from .control_data_classification import (
|
|
205
|
+
DataClassificationTaggingAssessment,
|
|
206
|
+
S3BucketClassificationTagsAssessment
|
|
207
|
+
)
|
|
208
|
+
from .control_network_security import (
|
|
209
|
+
NetworkFirewallDeployedAssessment,
|
|
210
|
+
Route53ResolverFirewallEnabledAssessment
|
|
211
|
+
)
|
|
212
|
+
from .control_backup_security import (
|
|
213
|
+
BackupVaultEncryptionEnabledAssessment,
|
|
214
|
+
BackupCrossRegionCopyEnabledAssessment,
|
|
215
|
+
BackupVaultLockEnabledAssessment,
|
|
216
|
+
Route53QueryLoggingEnabledAssessment,
|
|
217
|
+
RDSBackupRetentionCheckAssessment
|
|
218
|
+
)
|
|
219
|
+
|
|
146
220
|
__all__ = [
|
|
147
221
|
# Control 1.1 - Asset Inventory
|
|
148
222
|
'EIPAttachedAssessment',
|
|
@@ -171,13 +245,6 @@ __all__ = [
|
|
|
171
245
|
'RDSInstancePublicAccessCheckAssessment',
|
|
172
246
|
'RedshiftClusterPublicAccessCheckAssessment',
|
|
173
247
|
'S3BucketLevelPublicAccessProhibitedAssessment',
|
|
174
|
-
'DMSReplicationNotPublicAssessment',
|
|
175
|
-
'ElasticsearchInVPCOnlyAssessment',
|
|
176
|
-
'EC2InstancesInVPCAssessment',
|
|
177
|
-
'EMRMasterNoPublicIPAssessment',
|
|
178
|
-
'LambdaFunctionPublicAccessProhibitedAssessment',
|
|
179
|
-
'SageMakerNotebookNoDirectInternetAccessAssessment',
|
|
180
|
-
'SubnetAutoAssignPublicIPDisabledAssessment',
|
|
181
248
|
'IAMGroupHasUsersCheckAssessment',
|
|
182
249
|
'IAMPolicyNoStatementsWithFullAccessAssessment',
|
|
183
250
|
'IAMUserNoPoliciesCheckAssessment',
|
|
@@ -252,5 +319,67 @@ __all__ = [
|
|
|
252
319
|
'S3BucketPublicWriteProhibitedAssessment',
|
|
253
320
|
|
|
254
321
|
# Instance Optimization
|
|
255
|
-
'EBSOptimizedInstanceAssessment'
|
|
322
|
+
'EBSOptimizedInstanceAssessment',
|
|
323
|
+
|
|
324
|
+
# Phase 1-4: CIS Controls v8.1 IG1 Expansion (50 new rules)
|
|
325
|
+
# Phase 1 - Quick Wins (13 rules)
|
|
326
|
+
'GuardDutyEnabledAssessment',
|
|
327
|
+
'InspectorEnabledAssessment',
|
|
328
|
+
'MacieEnabledAssessment',
|
|
329
|
+
'IAMAccessAnalyzerEnabledAssessment',
|
|
330
|
+
'VPCFlowLogsEnabledAssessment',
|
|
331
|
+
'ELBLoggingEnabledAssessment',
|
|
332
|
+
'CloudFrontLoggingEnabledAssessment',
|
|
333
|
+
'WAFLoggingEnabledAssessment',
|
|
334
|
+
'EBSEncryptionByDefaultAssessment',
|
|
335
|
+
'RDSStorageEncryptedAssessment',
|
|
336
|
+
'EFSEncryptedCheckAssessment',
|
|
337
|
+
'DynamoDBTableEncryptedKMSAssessment',
|
|
338
|
+
'S3DefaultEncryptionKMSAssessment',
|
|
339
|
+
|
|
340
|
+
# Phase 2 - Core Security (15 rules)
|
|
341
|
+
'SSMPatchManagerEnabledAssessment',
|
|
342
|
+
'SSMPatchBaselineConfiguredAssessment',
|
|
343
|
+
'EC2PatchComplianceStatusAssessment',
|
|
344
|
+
'SSOEnabledCheckAssessment',
|
|
345
|
+
'IdentityCenterConfiguredAssessment',
|
|
346
|
+
'IAMAdminMFARequiredAssessment',
|
|
347
|
+
'CognitoMFAEnabledAssessment',
|
|
348
|
+
'VPNMFAEnabledAssessment',
|
|
349
|
+
'ALBHTTPToHTTPSRedirectionAssessment',
|
|
350
|
+
'ELBTLSHTTPSListenersOnlyAssessment',
|
|
351
|
+
'RDSSSLConnectionRequiredAssessment',
|
|
352
|
+
'APIGatewaySSLEnabledAssessment',
|
|
353
|
+
'RedshiftRequireTLSSSLAssessment',
|
|
354
|
+
'SNSEncryptedKMSAssessment',
|
|
355
|
+
'SQSQueueEncryptedAssessment',
|
|
356
|
+
'CloudTrailS3DataEventsEnabledAssessment',
|
|
357
|
+
|
|
358
|
+
# Phase 3 - Advanced (15 rules)
|
|
359
|
+
'SSMInventoryEnabledAssessment',
|
|
360
|
+
'ConfigEnabledAllRegionsAssessment',
|
|
361
|
+
'AMIInventoryTrackingAssessment',
|
|
362
|
+
'LambdaRuntimeInventoryAssessment',
|
|
363
|
+
'IAMUserInventoryCheckAssessment',
|
|
364
|
+
'ConfigConformancePackDeployedAssessment',
|
|
365
|
+
'SecurityHubStandardsEnabledAssessment',
|
|
366
|
+
'AssetTaggingComplianceAssessment',
|
|
367
|
+
'InspectorAssessmentEnabledAssessment',
|
|
368
|
+
'EC2OSVersionSupportedAssessment',
|
|
369
|
+
'RDSEngineVersionSupportedAssessment',
|
|
370
|
+
'LambdaRuntimeSupportedAssessment',
|
|
371
|
+
'IAMUserLastAccessCheckAssessment',
|
|
372
|
+
'SSMSessionManagerEnabledAssessment',
|
|
373
|
+
'UnauthorizedAssetDetectionAssessment',
|
|
374
|
+
|
|
375
|
+
# Phase 4 - Enhanced (7 rules)
|
|
376
|
+
'DataClassificationTaggingAssessment',
|
|
377
|
+
'S3BucketClassificationTagsAssessment',
|
|
378
|
+
'NetworkFirewallDeployedAssessment',
|
|
379
|
+
'Route53ResolverFirewallEnabledAssessment',
|
|
380
|
+
'BackupVaultEncryptionEnabledAssessment',
|
|
381
|
+
'BackupCrossRegionCopyEnabledAssessment',
|
|
382
|
+
'BackupVaultLockEnabledAssessment',
|
|
383
|
+
'Route53QueryLoggingEnabledAssessment',
|
|
384
|
+
'RDSBackupRetentionCheckAssessment'
|
|
256
385
|
]
|
|
@@ -28,8 +28,8 @@ class AccountPartOfOrganizationsAssessment(BaseConfigRuleAssessment):
|
|
|
28
28
|
return []
|
|
29
29
|
|
|
30
30
|
try:
|
|
31
|
-
# Get account information
|
|
32
|
-
sts_client = aws_factory.get_client('sts', region)
|
|
31
|
+
# Get account information (use allow_global_region for account-level resources)
|
|
32
|
+
sts_client = aws_factory.get_client('sts', region, allow_global_region=True)
|
|
33
33
|
|
|
34
34
|
response = aws_factory.aws_api_call_with_retry(
|
|
35
35
|
lambda: sts_client.get_caller_identity()
|
|
@@ -55,8 +55,8 @@ class AccountPartOfOrganizationsAssessment(BaseConfigRuleAssessment):
|
|
|
55
55
|
account_id = resource.get('AccountId', 'unknown')
|
|
56
56
|
|
|
57
57
|
try:
|
|
58
|
-
# Check if account is part of an organization
|
|
59
|
-
organizations_client = aws_factory.get_client('organizations', region)
|
|
58
|
+
# Check if account is part of an organization (use allow_global_region for account-level resources)
|
|
59
|
+
organizations_client = aws_factory.get_client('organizations', region, allow_global_region=True)
|
|
60
60
|
|
|
61
61
|
# Try to describe the organization
|
|
62
62
|
response = aws_factory.aws_api_call_with_retry(
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CIS Control 6.1 - IAM Access Analyzer
|
|
3
|
+
Ensures IAM Access Analyzer is enabled for access control validation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import List, Dict, Any
|
|
8
|
+
from botocore.exceptions import ClientError
|
|
9
|
+
|
|
10
|
+
from aws_cis_assessment.controls.base_control import BaseConfigRuleAssessment
|
|
11
|
+
from aws_cis_assessment.core.models import ComplianceResult, ComplianceStatus
|
|
12
|
+
from aws_cis_assessment.core.aws_client_factory import AWSClientFactory
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IAMAccessAnalyzerEnabledAssessment(BaseConfigRuleAssessment):
|
|
18
|
+
"""
|
|
19
|
+
CIS Control 6.1 - Establish an Access Granting Process
|
|
20
|
+
AWS Config Rule: iam-access-analyzer-enabled
|
|
21
|
+
|
|
22
|
+
Ensures IAM Access Analyzer is enabled to identify resources shared with
|
|
23
|
+
external entities. Access Analyzer helps identify unintended access to
|
|
24
|
+
resources and data, which is a security risk.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
super().__init__(
|
|
29
|
+
rule_name="iam-access-analyzer-enabled",
|
|
30
|
+
control_id="6.1",
|
|
31
|
+
resource_types=["AWS::AccessAnalyzer::Analyzer"]
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
|
|
35
|
+
"""Get IAM Access Analyzer configuration for the region."""
|
|
36
|
+
if resource_type != "AWS::AccessAnalyzer::Analyzer":
|
|
37
|
+
return []
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
access_analyzer_client = aws_factory.get_client('accessanalyzer', region)
|
|
41
|
+
|
|
42
|
+
# List all analyzers in the region
|
|
43
|
+
try:
|
|
44
|
+
response = access_analyzer_client.list_analyzers()
|
|
45
|
+
analyzers = response.get('analyzers', [])
|
|
46
|
+
|
|
47
|
+
if not analyzers:
|
|
48
|
+
# No analyzer found
|
|
49
|
+
return [{
|
|
50
|
+
'AnalyzerArn': 'none',
|
|
51
|
+
'AnalyzerName': 'none',
|
|
52
|
+
'Status': 'NOT_ENABLED',
|
|
53
|
+
'Type': 'UNKNOWN',
|
|
54
|
+
'Region': region,
|
|
55
|
+
'AccountId': aws_factory.get_account_info().get('account_id', 'unknown')
|
|
56
|
+
}]
|
|
57
|
+
|
|
58
|
+
# Return all analyzers
|
|
59
|
+
analyzer_resources = []
|
|
60
|
+
for analyzer in analyzers:
|
|
61
|
+
analyzer_resources.append({
|
|
62
|
+
'AnalyzerArn': analyzer.get('arn', ''),
|
|
63
|
+
'AnalyzerName': analyzer.get('name', ''),
|
|
64
|
+
'Status': analyzer.get('status', 'UNKNOWN'),
|
|
65
|
+
'Type': analyzer.get('type', 'UNKNOWN'),
|
|
66
|
+
'Region': region,
|
|
67
|
+
'AccountId': aws_factory.get_account_info().get('account_id', 'unknown'),
|
|
68
|
+
'CreatedAt': analyzer.get('createdAt', ''),
|
|
69
|
+
'LastResourceAnalyzed': analyzer.get('lastResourceAnalyzed', ''),
|
|
70
|
+
'LastResourceAnalyzedAt': analyzer.get('lastResourceAnalyzedAt', '')
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return analyzer_resources
|
|
74
|
+
|
|
75
|
+
except ClientError as e:
|
|
76
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
77
|
+
if error_code in ['ResourceNotFoundException', 'AccessDeniedException']:
|
|
78
|
+
# No analyzer or no access
|
|
79
|
+
return [{
|
|
80
|
+
'AnalyzerArn': 'none',
|
|
81
|
+
'AnalyzerName': 'none',
|
|
82
|
+
'Status': 'NOT_ENABLED',
|
|
83
|
+
'Type': 'UNKNOWN',
|
|
84
|
+
'Region': region,
|
|
85
|
+
'AccountId': aws_factory.get_account_info().get('account_id', 'unknown')
|
|
86
|
+
}]
|
|
87
|
+
raise
|
|
88
|
+
|
|
89
|
+
except ClientError as e:
|
|
90
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
91
|
+
if error_code == 'AccessDeniedException':
|
|
92
|
+
logger.warning(f"Access denied to IAM Access Analyzer in {region}")
|
|
93
|
+
else:
|
|
94
|
+
logger.error(f"Error checking IAM Access Analyzer status in {region}: {e}")
|
|
95
|
+
return []
|
|
96
|
+
|
|
97
|
+
def _evaluate_resource_compliance(
|
|
98
|
+
self,
|
|
99
|
+
resource: Dict[str, Any],
|
|
100
|
+
aws_factory: AWSClientFactory,
|
|
101
|
+
region: str
|
|
102
|
+
) -> ComplianceResult:
|
|
103
|
+
"""Evaluate if IAM Access Analyzer is enabled."""
|
|
104
|
+
analyzer_name = resource.get('AnalyzerName', 'none')
|
|
105
|
+
analyzer_arn = resource.get('AnalyzerArn', 'none')
|
|
106
|
+
status = resource.get('Status', 'NOT_ENABLED')
|
|
107
|
+
analyzer_type = resource.get('Type', 'UNKNOWN')
|
|
108
|
+
|
|
109
|
+
# Check if Access Analyzer is enabled and active
|
|
110
|
+
is_compliant = status == 'ACTIVE' and analyzer_type in ['ACCOUNT', 'ORGANIZATION']
|
|
111
|
+
|
|
112
|
+
if is_compliant:
|
|
113
|
+
evaluation_reason = (
|
|
114
|
+
f"IAM Access Analyzer '{analyzer_name}' is active in {region}. "
|
|
115
|
+
f"Type: {analyzer_type}"
|
|
116
|
+
)
|
|
117
|
+
compliance_status = ComplianceStatus.COMPLIANT
|
|
118
|
+
else:
|
|
119
|
+
if analyzer_name == 'none' or status == 'NOT_ENABLED':
|
|
120
|
+
evaluation_reason = f"IAM Access Analyzer is not enabled in {region}."
|
|
121
|
+
elif status == 'CREATING':
|
|
122
|
+
evaluation_reason = f"IAM Access Analyzer '{analyzer_name}' is being created in {region}."
|
|
123
|
+
compliance_status = ComplianceStatus.NON_COMPLIANT
|
|
124
|
+
elif status == 'FAILED':
|
|
125
|
+
evaluation_reason = f"IAM Access Analyzer '{analyzer_name}' failed to create in {region}."
|
|
126
|
+
compliance_status = ComplianceStatus.NON_COMPLIANT
|
|
127
|
+
else:
|
|
128
|
+
evaluation_reason = f"IAM Access Analyzer '{analyzer_name}' status is {status} in {region}."
|
|
129
|
+
compliance_status = ComplianceStatus.NON_COMPLIANT
|
|
130
|
+
|
|
131
|
+
if not is_compliant:
|
|
132
|
+
compliance_status = ComplianceStatus.NON_COMPLIANT
|
|
133
|
+
|
|
134
|
+
return ComplianceResult(
|
|
135
|
+
resource_id=analyzer_arn if analyzer_arn != 'none' else 'none',
|
|
136
|
+
resource_type="AWS::AccessAnalyzer::Analyzer",
|
|
137
|
+
compliance_status=compliance_status,
|
|
138
|
+
evaluation_reason=evaluation_reason,
|
|
139
|
+
config_rule_name=self.rule_name,
|
|
140
|
+
region=region
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
def _get_rule_remediation_steps(self) -> List[str]:
|
|
144
|
+
"""Get remediation steps for enabling IAM Access Analyzer."""
|
|
145
|
+
return [
|
|
146
|
+
"1. Enable IAM Access Analyzer in the AWS Console:",
|
|
147
|
+
" - Navigate to IAM service",
|
|
148
|
+
" - Click 'Access analyzer' in the left menu",
|
|
149
|
+
" - Click 'Create analyzer'",
|
|
150
|
+
" - Choose analyzer type:",
|
|
151
|
+
" * Account: Analyzes resources in current account",
|
|
152
|
+
" * Organization: Analyzes resources across AWS Organization",
|
|
153
|
+
" - Enter analyzer name",
|
|
154
|
+
" - Click 'Create analyzer'",
|
|
155
|
+
"",
|
|
156
|
+
"2. Enable Access Analyzer using AWS CLI:",
|
|
157
|
+
" # For account-level analyzer",
|
|
158
|
+
" aws accessanalyzer create-analyzer \\",
|
|
159
|
+
" --analyzer-name MyAccountAnalyzer \\",
|
|
160
|
+
" --type ACCOUNT \\",
|
|
161
|
+
" --region <region>",
|
|
162
|
+
"",
|
|
163
|
+
" # For organization-level analyzer (requires AWS Organizations)",
|
|
164
|
+
" aws accessanalyzer create-analyzer \\",
|
|
165
|
+
" --analyzer-name MyOrgAnalyzer \\",
|
|
166
|
+
" --type ORGANIZATION \\",
|
|
167
|
+
" --region <region>",
|
|
168
|
+
"",
|
|
169
|
+
"3. Review findings:",
|
|
170
|
+
" - Access Analyzer automatically scans resources",
|
|
171
|
+
" - Review findings in IAM console under 'Access analyzer'",
|
|
172
|
+
" - Findings show resources accessible from outside your account/org",
|
|
173
|
+
"",
|
|
174
|
+
"4. Resolve findings:",
|
|
175
|
+
" - Active findings: Resources with external access",
|
|
176
|
+
" - Archived findings: Previously resolved or accepted risks",
|
|
177
|
+
" - For each finding:",
|
|
178
|
+
" * Review the resource and access path",
|
|
179
|
+
" * Determine if access is intended",
|
|
180
|
+
" * If unintended: Remove the external access",
|
|
181
|
+
" * If intended: Archive the finding with justification",
|
|
182
|
+
"",
|
|
183
|
+
"5. Set up notifications:",
|
|
184
|
+
" - Create EventBridge rules to route findings to SNS/Slack",
|
|
185
|
+
" - Configure alerts for new findings",
|
|
186
|
+
"",
|
|
187
|
+
"6. Best practices:",
|
|
188
|
+
" - Enable in all regions where you have resources",
|
|
189
|
+
" - Review findings weekly",
|
|
190
|
+
" - Use organization analyzer for centralized visibility",
|
|
191
|
+
" - Integrate with Security Hub for consolidated findings",
|
|
192
|
+
"",
|
|
193
|
+
"Priority: HIGH - Unintended external access is a critical security risk",
|
|
194
|
+
"Effort: Low - Can be enabled in minutes",
|
|
195
|
+
"",
|
|
196
|
+
"AWS Documentation:",
|
|
197
|
+
"https://docs.aws.amazon.com/IAM/latest/UserGuide/what-is-access-analyzer.html"
|
|
198
|
+
]
|