aws-cis-controls-assessment 1.0.9__py3-none-any.whl → 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aws_cis_assessment/__init__.py +2 -2
- aws_cis_assessment/config/rules/cis_controls_ig1.yaml +94 -1
- aws_cis_assessment/config/rules/cis_controls_ig2.yaml +680 -1
- aws_cis_assessment/controls/ig1/__init__.py +17 -0
- aws_cis_assessment/controls/ig1/control_aws_backup_service.py +1276 -0
- aws_cis_assessment/controls/ig2/__init__.py +74 -1
- aws_cis_assessment/controls/ig2/control_4_5_6_access_configuration.py +2638 -0
- aws_cis_assessment/controls/ig2/control_8_audit_logging.py +984 -0
- aws_cis_assessment/controls/ig2/control_aws_backup_ig2.py +23 -0
- aws_cis_assessment/core/assessment_engine.py +74 -0
- aws_cis_assessment/reporters/html_reporter.py +197 -35
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/METADATA +163 -12
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/RECORD +26 -21
- docs/README.md +14 -3
- docs/adding-aws-backup-controls.md +562 -0
- docs/assessment-logic.md +291 -3
- docs/cli-reference.md +1 -1
- docs/config-rule-mappings.md +465 -7
- docs/developer-guide.md +312 -3
- docs/installation.md +2 -2
- docs/troubleshooting.md +211 -2
- docs/user-guide.md +47 -2
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/WHEEL +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/entry_points.txt +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {aws_cis_controls_assessment-1.0.9.dist-info → aws_cis_controls_assessment-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -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.
|