aws-cis-controls-assessment 1.0.9__py3-none-any.whl → 1.0.10__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.
@@ -0,0 +1,562 @@
1
+ # Adding AWS Backup Service Controls
2
+
3
+ ## Overview
4
+
5
+ This guide explains how to add comprehensive AWS Backup service controls to the assessment tool. The tool currently has **resource-specific backup controls** (e.g., `dynamodb-in-backup-plan`, `ebs-in-backup-plan`) that check if individual resources are protected. We'll add **AWS Backup service-level controls** that assess the backup infrastructure itself.
6
+
7
+ ## Current State Analysis
8
+
9
+ ### Existing Backup Controls
10
+
11
+ The tool currently has **9 backup-related controls** across different services:
12
+
13
+ **IG1 Controls (Control 11.2 - Perform Automated Backups):**
14
+ 1. `dynamodb-in-backup-plan` - Checks if DynamoDB tables are in backup plans
15
+ 2. `ebs-in-backup-plan` - Checks if EBS volumes are in backup plans
16
+ 3. `efs-in-backup-plan` - Checks if EFS file systems are in backup plans
17
+ 4. `db-instance-backup-enabled` - Checks if RDS instances have backups enabled
18
+ 5. `redshift-backup-enabled` - Checks if Redshift clusters have automated snapshots
19
+ 6. `dynamodb-pitr-enabled` - Checks if DynamoDB has point-in-time recovery
20
+ 7. `elasticache-redis-cluster-automatic-backup-check` - Checks ElastiCache Redis backups
21
+ 8. `s3-bucket-replication-enabled` - Checks if S3 buckets have replication
22
+
23
+ **IG2 Controls (Control 3.11 - Encrypt Sensitive Data at Rest):**
24
+ 9. `backup-recovery-point-encrypted` - Checks if AWS Backup recovery points are encrypted
25
+
26
+ ### Architecture Pattern
27
+
28
+ Current controls follow this pattern:
29
+ - **Resource-centric**: Check individual resources (DynamoDB tables, EBS volumes, etc.)
30
+ - **Service-specific**: Each service has its own backup mechanism
31
+ - **Distributed**: Backup logic spread across multiple control files
32
+
33
+ ## Proposed AWS Backup Service Controls
34
+
35
+ ### New Resource Types to Add
36
+
37
+ AWS Backup provides centralized backup management. We should add controls for:
38
+
39
+ 1. **AWS::Backup::BackupPlan** - Backup plan configuration and policies
40
+ 2. **AWS::Backup::BackupSelection** - Resource selection for backup plans
41
+ 3. **AWS::Backup::BackupVault** - Backup storage vaults and access policies
42
+ 4. **AWS::Backup::RecoveryPoint** - Individual backup recovery points (already exists)
43
+ 5. **AWS::Backup::ReportPlan** - Backup compliance reporting
44
+ 6. **AWS::Backup::RestoreTestingPlan** - Automated restore testing
45
+
46
+ ### Recommended Approach: Hybrid Model
47
+
48
+ **Keep existing resource-specific controls** AND **add AWS Backup service controls**
49
+
50
+ #### Why Hybrid?
51
+
52
+ 1. **Complementary Coverage**:
53
+ - Resource controls: "Is this DynamoDB table backed up?"
54
+ - Service controls: "Is the backup infrastructure properly configured?"
55
+
56
+ 2. **Different Use Cases**:
57
+ - Resource controls: Operational compliance (are resources protected?)
58
+ - Service controls: Infrastructure compliance (is backup system secure?)
59
+
60
+ 3. **Flexibility**:
61
+ - Some organizations use AWS Backup centrally
62
+ - Others use service-native backup features
63
+ - Hybrid approach covers both scenarios
64
+
65
+ ## Implementation Strategy
66
+
67
+ ### Phase 1: Add Core AWS Backup Service Controls
68
+
69
+ Create a new control file: `control_aws_backup_service.py`
70
+
71
+ **Recommended Controls:**
72
+
73
+ 1. **backup-plan-min-frequency-and-min-retention-check**
74
+ - Resource: `AWS::Backup::BackupPlan`
75
+ - Validates backup frequency and retention policies
76
+ - Ensures backups happen regularly and are retained appropriately
77
+
78
+ 2. **backup-vault-access-policy-check**
79
+ - Resource: `AWS::Backup::BackupVault`
80
+ - Checks vault access policies for security
81
+ - Ensures vaults aren't publicly accessible
82
+
83
+ 3. **backup-vault-lock-check**
84
+ - Resource: `AWS::Backup::BackupVault`
85
+ - Verifies vault lock is enabled (prevents deletion)
86
+ - Critical for ransomware protection
87
+
88
+ 4. **backup-selection-resource-coverage-check**
89
+ - Resource: `AWS::Backup::BackupSelection`
90
+ - Validates that backup selections cover critical resources
91
+ - Ensures no resources are accidentally excluded
92
+
93
+ 5. **backup-report-plan-exists-check**
94
+ - Resource: `AWS::Backup::ReportPlan`
95
+ - Checks if backup reporting is configured
96
+ - Ensures backup compliance monitoring
97
+
98
+ 6. **backup-restore-testing-plan-exists-check**
99
+ - Resource: `AWS::Backup::RestoreTestingPlan`
100
+ - Verifies restore testing is configured
101
+ - Ensures backups are actually recoverable
102
+
103
+ ### Phase 2: Enhance Existing Controls
104
+
105
+ Improve existing resource-specific controls to actually check AWS Backup:
106
+
107
+ **Current Issue**: Many controls have placeholder implementations:
108
+ ```python
109
+ # For simplicity, assume compliant - full implementation would check backup plans
110
+ compliance_status = ComplianceStatus.COMPLIANT
111
+ ```
112
+
113
+ **Enhancement**: Actually query AWS Backup API to verify protection:
114
+ ```python
115
+ # Check if resource is actually protected by AWS Backup
116
+ backup_client = aws_factory.get_client('backup', region)
117
+ protected = backup_client.describe_protected_resource(
118
+ ResourceArn=resource_arn
119
+ )
120
+ ```
121
+
122
+ ### Phase 3: Add to Configuration
123
+
124
+ Update YAML configuration files to include new controls.
125
+
126
+ ## Detailed Implementation Guide
127
+
128
+ ### Step 1: Create New Control File
129
+
130
+ Create `aws_cis_assessment/controls/ig1/control_aws_backup_service.py`:
131
+
132
+ ```python
133
+ """AWS Backup Service Controls - Centralized backup infrastructure assessment."""
134
+
135
+ from typing import Dict, List, Any
136
+ import logging
137
+ from botocore.exceptions import ClientError
138
+
139
+ from aws_cis_assessment.controls.base_control import BaseConfigRuleAssessment
140
+ from aws_cis_assessment.core.models import ComplianceResult, ComplianceStatus
141
+ from aws_cis_assessment.core.aws_client_factory import AWSClientFactory
142
+
143
+ logger = logging.getLogger(__name__)
144
+
145
+
146
+ class BackupPlanMinFrequencyAndMinRetentionCheckAssessment(BaseConfigRuleAssessment):
147
+ """Assessment for backup-plan-min-frequency-and-min-retention-check Config rule."""
148
+
149
+ def __init__(self):
150
+ super().__init__(
151
+ rule_name="backup-plan-min-frequency-and-min-retention-check",
152
+ control_id="11.2",
153
+ resource_types=["AWS::Backup::BackupPlan"]
154
+ )
155
+
156
+ def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
157
+ """Get all AWS Backup plans in the region."""
158
+ if resource_type != "AWS::Backup::BackupPlan":
159
+ return []
160
+
161
+ try:
162
+ backup_client = aws_factory.get_client('backup', region)
163
+
164
+ response = aws_factory.aws_api_call_with_retry(
165
+ lambda: backup_client.list_backup_plans()
166
+ )
167
+
168
+ plans = []
169
+ for plan in response.get('BackupPlansList', []):
170
+ # Get detailed plan information
171
+ plan_id = plan.get('BackupPlanId')
172
+ plan_details = aws_factory.aws_api_call_with_retry(
173
+ lambda: backup_client.get_backup_plan(BackupPlanId=plan_id)
174
+ )
175
+
176
+ plans.append({
177
+ 'BackupPlanId': plan_id,
178
+ 'BackupPlanName': plan.get('BackupPlanName'),
179
+ 'BackupPlan': plan_details.get('BackupPlan'),
180
+ 'VersionId': plan.get('VersionId')
181
+ })
182
+
183
+ return plans
184
+
185
+ except ClientError as e:
186
+ logger.error(f"Error retrieving backup plans in region {region}: {e}")
187
+ raise
188
+
189
+ def _evaluate_resource_compliance(self, resource: Dict[str, Any], aws_factory: AWSClientFactory, region: str) -> ComplianceResult:
190
+ """Evaluate if backup plan has appropriate frequency and retention."""
191
+ plan_id = resource.get('BackupPlanId', 'unknown')
192
+ plan_name = resource.get('BackupPlanName', 'unknown')
193
+ backup_plan = resource.get('BackupPlan', {})
194
+
195
+ # Check backup rules
196
+ rules = backup_plan.get('Rules', [])
197
+
198
+ if not rules:
199
+ compliance_status = ComplianceStatus.NON_COMPLIANT
200
+ evaluation_reason = f"Backup plan {plan_name} has no backup rules defined"
201
+ else:
202
+ # Validate each rule has appropriate frequency and retention
203
+ # Minimum: Daily backups, 7 days retention
204
+ compliant_rules = 0
205
+ issues = []
206
+
207
+ for rule in rules:
208
+ rule_name = rule.get('RuleName', 'unnamed')
209
+ schedule = rule.get('ScheduleExpression', '')
210
+ retention_days = rule.get('Lifecycle', {}).get('DeleteAfterDays', 0)
211
+
212
+ # Check frequency (should be at least daily)
213
+ if 'cron' in schedule.lower() or 'rate' in schedule.lower():
214
+ # Basic validation - full implementation would parse schedule
215
+ has_valid_frequency = True
216
+ else:
217
+ has_valid_frequency = False
218
+ issues.append(f"Rule '{rule_name}' has invalid schedule")
219
+
220
+ # Check retention (should be at least 7 days)
221
+ if retention_days >= 7:
222
+ has_valid_retention = True
223
+ else:
224
+ has_valid_retention = False
225
+ issues.append(f"Rule '{rule_name}' has insufficient retention ({retention_days} days)")
226
+
227
+ if has_valid_frequency and has_valid_retention:
228
+ compliant_rules += 1
229
+
230
+ if compliant_rules == len(rules):
231
+ compliance_status = ComplianceStatus.COMPLIANT
232
+ evaluation_reason = f"Backup plan {plan_name} has {len(rules)} compliant rule(s)"
233
+ else:
234
+ compliance_status = ComplianceStatus.NON_COMPLIANT
235
+ evaluation_reason = f"Backup plan {plan_name} has issues: {'; '.join(issues)}"
236
+
237
+ return ComplianceResult(
238
+ resource_id=plan_id,
239
+ resource_type="AWS::Backup::BackupPlan",
240
+ compliance_status=compliance_status,
241
+ evaluation_reason=evaluation_reason,
242
+ config_rule_name=self.rule_name,
243
+ region=region
244
+ )
245
+
246
+
247
+ class BackupVaultAccessPolicyCheckAssessment(BaseConfigRuleAssessment):
248
+ """Assessment for backup-vault-access-policy-check Config rule."""
249
+
250
+ def __init__(self):
251
+ super().__init__(
252
+ rule_name="backup-vault-access-policy-check",
253
+ control_id="11.2",
254
+ resource_types=["AWS::Backup::BackupVault"]
255
+ )
256
+
257
+ def _get_resources(self, aws_factory: AWSClientFactory, resource_type: str, region: str) -> List[Dict[str, Any]]:
258
+ """Get all AWS Backup vaults in the region."""
259
+ if resource_type != "AWS::Backup::BackupVault":
260
+ return []
261
+
262
+ try:
263
+ backup_client = aws_factory.get_client('backup', region)
264
+
265
+ response = aws_factory.aws_api_call_with_retry(
266
+ lambda: backup_client.list_backup_vaults()
267
+ )
268
+
269
+ vaults = []
270
+ for vault in response.get('BackupVaultList', []):
271
+ vault_name = vault.get('BackupVaultName')
272
+
273
+ # Get vault access policy
274
+ try:
275
+ policy_response = aws_factory.aws_api_call_with_retry(
276
+ lambda: backup_client.get_backup_vault_access_policy(
277
+ BackupVaultName=vault_name
278
+ )
279
+ )
280
+ vault['AccessPolicy'] = policy_response.get('Policy')
281
+ except ClientError as e:
282
+ if e.response.get('Error', {}).get('Code') == 'ResourceNotFoundException':
283
+ vault['AccessPolicy'] = None
284
+ else:
285
+ raise
286
+
287
+ vaults.append(vault)
288
+
289
+ return vaults
290
+
291
+ except ClientError as e:
292
+ logger.error(f"Error retrieving backup vaults in region {region}: {e}")
293
+ raise
294
+
295
+ def _evaluate_resource_compliance(self, resource: Dict[str, Any], aws_factory: AWSClientFactory, region: str) -> ComplianceResult:
296
+ """Evaluate if backup vault has secure access policy."""
297
+ vault_name = resource.get('BackupVaultName', 'unknown')
298
+ access_policy = resource.get('AccessPolicy')
299
+
300
+ if not access_policy:
301
+ # No policy means default deny - this is secure
302
+ compliance_status = ComplianceStatus.COMPLIANT
303
+ evaluation_reason = f"Backup vault {vault_name} has no access policy (default deny)"
304
+ else:
305
+ # Check for overly permissive policies
306
+ import json
307
+ try:
308
+ policy_doc = json.loads(access_policy)
309
+ statements = policy_doc.get('Statement', [])
310
+
311
+ # Check for public access
312
+ has_public_access = False
313
+ for statement in statements:
314
+ principal = statement.get('Principal', {})
315
+ if principal == '*' or principal.get('AWS') == '*':
316
+ has_public_access = True
317
+ break
318
+
319
+ if has_public_access:
320
+ compliance_status = ComplianceStatus.NON_COMPLIANT
321
+ evaluation_reason = f"Backup vault {vault_name} has overly permissive access policy (allows public access)"
322
+ else:
323
+ compliance_status = ComplianceStatus.COMPLIANT
324
+ evaluation_reason = f"Backup vault {vault_name} has appropriate access policy"
325
+
326
+ except json.JSONDecodeError:
327
+ compliance_status = ComplianceStatus.ERROR
328
+ evaluation_reason = f"Backup vault {vault_name} has invalid access policy JSON"
329
+
330
+ return ComplianceResult(
331
+ resource_id=vault_name,
332
+ resource_type="AWS::Backup::BackupVault",
333
+ compliance_status=compliance_status,
334
+ evaluation_reason=evaluation_reason,
335
+ config_rule_name=self.rule_name,
336
+ region=region
337
+ )
338
+ ```
339
+
340
+ ### Step 2: Register New Controls
341
+
342
+ Update `aws_cis_assessment/core/assessment_engine.py`:
343
+
344
+ ```python
345
+ # Add import
346
+ from aws_cis_assessment.controls.ig1.control_aws_backup_service import (
347
+ BackupPlanMinFrequencyAndMinRetentionCheckAssessment,
348
+ BackupVaultAccessPolicyCheckAssessment,
349
+ # ... other new assessments
350
+ )
351
+
352
+ # Add to assessments dictionary
353
+ 'backup-plan-min-frequency-and-min-retention-check': BackupPlanMinFrequencyAndMinRetentionCheckAssessment(),
354
+ 'backup-vault-access-policy-check': BackupVaultAccessPolicyCheckAssessment(),
355
+ ```
356
+
357
+ ### Step 3: Update YAML Configuration
358
+
359
+ Add to `aws_cis_assessment/config/rules/cis_controls_ig1.yaml`:
360
+
361
+ ```yaml
362
+ - name: backup-plan-min-frequency-and-min-retention-check
363
+ resource_types:
364
+ - AWS::Backup::BackupPlan
365
+ parameters: {}
366
+ description: Validates AWS Backup plans have appropriate backup frequency and retention policies
367
+ remediation_guidance: |
368
+ Ensure backup plans have:
369
+ - Backup frequency of at least daily
370
+ - Retention period of at least 7 days
371
+ - Appropriate lifecycle policies
372
+
373
+ - name: backup-vault-access-policy-check
374
+ resource_types:
375
+ - AWS::Backup::BackupVault
376
+ parameters: {}
377
+ description: Checks AWS Backup vault access policies for security
378
+ remediation_guidance: |
379
+ Ensure backup vaults:
380
+ - Do not allow public access
381
+ - Have restrictive access policies
382
+ - Follow principle of least privilege
383
+ ```
384
+
385
+ ### Step 4: Update IAM Permissions
386
+
387
+ The `backup` service is already included in the IAM policy, but verify these actions are covered:
388
+
389
+ ```json
390
+ {
391
+ "Effect": "Allow",
392
+ "Action": [
393
+ "backup:ListBackupPlans",
394
+ "backup:GetBackupPlan",
395
+ "backup:ListBackupVaults",
396
+ "backup:GetBackupVaultAccessPolicy",
397
+ "backup:ListBackupSelections",
398
+ "backup:GetBackupSelection",
399
+ "backup:ListRecoveryPointsByBackupVault",
400
+ "backup:DescribeRecoveryPoint",
401
+ "backup:ListReportPlans",
402
+ "backup:DescribeReportPlan",
403
+ "backup:ListRestoreTestingPlans",
404
+ "backup:GetRestoreTestingPlan",
405
+ "backup:DescribeProtectedResource"
406
+ ],
407
+ "Resource": "*"
408
+ }
409
+ ```
410
+
411
+ ## Control Mapping Strategy
412
+
413
+ ### Recommended CIS Controls Mapping
414
+
415
+ Map new AWS Backup controls to appropriate CIS Controls:
416
+
417
+ **Control 11.2 - Perform Automated Backups:**
418
+ - `backup-plan-min-frequency-and-min-retention-check` (IG1)
419
+ - `backup-selection-resource-coverage-check` (IG1)
420
+ - `backup-restore-testing-plan-exists-check` (IG2)
421
+
422
+ **Control 11.3 - Protect Recovery Data:**
423
+ - `backup-vault-access-policy-check` (IG1)
424
+ - `backup-vault-lock-check` (IG2)
425
+ - `backup-recovery-point-encrypted` (IG2) - already exists
426
+
427
+ **Control 11.5 - Test Data Recovery:**
428
+ - `backup-restore-testing-plan-exists-check` (IG2)
429
+
430
+ **Control 3.11 - Encrypt Sensitive Data at Rest:**
431
+ - `backup-recovery-point-encrypted` (IG2) - already exists
432
+
433
+ ## Testing Strategy
434
+
435
+ ### Unit Tests
436
+
437
+ Create `tests/test_aws_backup_service_controls.py`:
438
+
439
+ ```python
440
+ import pytest
441
+ from unittest.mock import Mock, patch
442
+ from aws_cis_assessment.controls.ig1.control_aws_backup_service import (
443
+ BackupPlanMinFrequencyAndMinRetentionCheckAssessment
444
+ )
445
+
446
+ def test_backup_plan_with_valid_rules():
447
+ """Test backup plan with valid frequency and retention."""
448
+ assessment = BackupPlanMinFrequencyAndMinRetentionCheckAssessment()
449
+
450
+ resource = {
451
+ 'BackupPlanId': 'plan-123',
452
+ 'BackupPlanName': 'daily-backup',
453
+ 'BackupPlan': {
454
+ 'Rules': [{
455
+ 'RuleName': 'daily-rule',
456
+ 'ScheduleExpression': 'cron(0 5 * * ? *)',
457
+ 'Lifecycle': {'DeleteAfterDays': 30}
458
+ }]
459
+ }
460
+ }
461
+
462
+ # Test evaluation logic
463
+ # ...
464
+ ```
465
+
466
+ ### Integration Tests
467
+
468
+ Test with real AWS Backup resources in a test account.
469
+
470
+ ## Migration Path
471
+
472
+ ### For Existing Users
473
+
474
+ 1. **No Breaking Changes**: Existing controls continue to work
475
+ 2. **Gradual Adoption**: New controls are additive
476
+ 3. **Backward Compatible**: Reports include both old and new controls
477
+
478
+ ### Deprecation Strategy (Optional)
479
+
480
+ If you want to eventually consolidate:
481
+
482
+ 1. **Phase 1** (Current): Keep both resource-specific and service controls
483
+ 2. **Phase 2** (Future): Mark resource-specific controls as "legacy"
484
+ 3. **Phase 3** (Later): Optionally deprecate duplicates
485
+
486
+ **Recommendation**: Keep both indefinitely - they serve different purposes.
487
+
488
+ ## Benefits of This Approach
489
+
490
+ ### 1. Comprehensive Coverage
491
+ - **Resource-level**: "Is this specific DynamoDB table backed up?"
492
+ - **Service-level**: "Is the backup infrastructure properly configured?"
493
+
494
+ ### 2. Flexibility
495
+ - Organizations using AWS Backup centrally get service-level insights
496
+ - Organizations using service-native backups get resource-level insights
497
+ - Both approaches are validated
498
+
499
+ ### 3. Security Depth
500
+ - Validates not just that backups exist, but that backup infrastructure is secure
501
+ - Checks vault access policies, encryption, restore testing
502
+
503
+ ### 4. Operational Excellence
504
+ - Ensures backup plans have appropriate frequency and retention
505
+ - Validates restore testing is configured
506
+ - Checks backup reporting for compliance monitoring
507
+
508
+ ## Example: Complete Control Flow
509
+
510
+ ```
511
+ User runs assessment
512
+
513
+ Resource-Specific Controls Execute:
514
+ - dynamodb-in-backup-plan: "Is table X in a backup plan?"
515
+ - ebs-in-backup-plan: "Is volume Y in a backup plan?"
516
+
517
+ Service-Level Controls Execute:
518
+ - backup-plan-min-frequency-and-min-retention-check: "Do backup plans have good policies?"
519
+ - backup-vault-access-policy-check: "Are backup vaults secure?"
520
+ - backup-restore-testing-plan-exists-check: "Can we actually restore?"
521
+
522
+ Report Generated:
523
+ - Shows both resource protection status AND backup infrastructure health
524
+ - Provides comprehensive backup compliance view
525
+ ```
526
+
527
+ ## Next Steps
528
+
529
+ 1. **Start with Core Controls**: Implement 2-3 most critical controls first
530
+ 2. **Test Thoroughly**: Validate with real AWS Backup resources
531
+ 3. **Document Well**: Update user guide with new controls
532
+ 4. **Gather Feedback**: See which controls users find most valuable
533
+ 5. **Iterate**: Add more controls based on user needs
534
+
535
+ ## Questions to Consider
536
+
537
+ 1. **Which controls are most critical for your use case?**
538
+ - Backup plan validation?
539
+ - Vault security?
540
+ - Restore testing?
541
+
542
+ 2. **What's your priority?**
543
+ - Quick wins (add 1-2 controls)?
544
+ - Comprehensive coverage (add all 6 controls)?
545
+
546
+ 3. **Do you want to enhance existing controls?**
547
+ - Fix placeholder implementations?
548
+ - Add actual AWS Backup API checks?
549
+
550
+ ## Conclusion
551
+
552
+ The hybrid approach (keeping resource-specific controls + adding service-level controls) provides:
553
+ - **Best coverage**: Both resource and infrastructure validation
554
+ - **Flexibility**: Works for different backup strategies
555
+ - **No breaking changes**: Existing functionality preserved
556
+ - **Enhanced security**: Deeper backup infrastructure assessment
557
+
558
+ This approach aligns with the tool's existing architecture and provides maximum value to users.
559
+
560
+ ---
561
+
562
+ **Ready to implement?** Start with `BackupPlanMinFrequencyAndMinRetentionCheckAssessment` and `BackupVaultAccessPolicyCheckAssessment` as they provide immediate security value.