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.
Files changed (45) hide show
  1. aws_cis_assessment/__init__.py +4 -4
  2. aws_cis_assessment/config/rules/cis_controls_ig1.yaml +365 -2
  3. aws_cis_assessment/controls/base_control.py +106 -24
  4. aws_cis_assessment/controls/ig1/__init__.py +144 -15
  5. aws_cis_assessment/controls/ig1/control_4_1.py +4 -4
  6. aws_cis_assessment/controls/ig1/control_access_analyzer.py +198 -0
  7. aws_cis_assessment/controls/ig1/control_access_asset_mgmt.py +360 -0
  8. aws_cis_assessment/controls/ig1/control_access_control.py +323 -0
  9. aws_cis_assessment/controls/ig1/control_backup_security.py +579 -0
  10. aws_cis_assessment/controls/ig1/control_cloudfront_logging.py +215 -0
  11. aws_cis_assessment/controls/ig1/control_configuration_mgmt.py +407 -0
  12. aws_cis_assessment/controls/ig1/control_data_classification.py +255 -0
  13. aws_cis_assessment/controls/ig1/control_dynamodb_encryption.py +279 -0
  14. aws_cis_assessment/controls/ig1/control_ebs_encryption.py +177 -0
  15. aws_cis_assessment/controls/ig1/control_efs_encryption.py +243 -0
  16. aws_cis_assessment/controls/ig1/control_elb_logging.py +195 -0
  17. aws_cis_assessment/controls/ig1/control_guardduty.py +156 -0
  18. aws_cis_assessment/controls/ig1/control_inspector.py +184 -0
  19. aws_cis_assessment/controls/ig1/control_inventory.py +511 -0
  20. aws_cis_assessment/controls/ig1/control_macie.py +165 -0
  21. aws_cis_assessment/controls/ig1/control_messaging_encryption.py +419 -0
  22. aws_cis_assessment/controls/ig1/control_mfa.py +485 -0
  23. aws_cis_assessment/controls/ig1/control_network_security.py +194 -619
  24. aws_cis_assessment/controls/ig1/control_patch_management.py +626 -0
  25. aws_cis_assessment/controls/ig1/control_rds_encryption.py +228 -0
  26. aws_cis_assessment/controls/ig1/control_s3_encryption.py +383 -0
  27. aws_cis_assessment/controls/ig1/control_tls_ssl.py +556 -0
  28. aws_cis_assessment/controls/ig1/control_version_mgmt.py +337 -0
  29. aws_cis_assessment/controls/ig1/control_vpc_flow_logs.py +205 -0
  30. aws_cis_assessment/controls/ig1/control_waf_logging.py +226 -0
  31. aws_cis_assessment/core/assessment_engine.py +160 -11
  32. aws_cis_assessment/core/aws_client_factory.py +17 -5
  33. aws_cis_assessment/core/models.py +20 -1
  34. aws_cis_assessment/core/scoring_engine.py +102 -1
  35. aws_cis_assessment/reporters/base_reporter.py +58 -13
  36. aws_cis_assessment/reporters/html_reporter.py +186 -9
  37. aws_cis_controls_assessment-1.2.2.dist-info/METADATA +320 -0
  38. {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/RECORD +44 -20
  39. docs/developer-guide.md +204 -5
  40. docs/user-guide.md +137 -4
  41. aws_cis_controls_assessment-1.1.4.dist-info/METADATA +0 -404
  42. {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/WHEEL +0 -0
  43. {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/entry_points.txt +0 -0
  44. {aws_cis_controls_assessment-1.1.4.dist-info → aws_cis_controls_assessment-1.2.2.dist-info}/licenses/LICENSE +0 -0
  45. {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
- DMSReplicationNotPublicAssessment,
65
- ElasticsearchInVPCOnlyAssessment,
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
+ ]