runbooks 1.1.4__py3-none-any.whl ā 1.1.5__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.
- runbooks/__init__.py +31 -2
- runbooks/__init___optimized.py +18 -4
- runbooks/_platform/__init__.py +1 -5
- runbooks/_platform/core/runbooks_wrapper.py +141 -138
- runbooks/aws2/accuracy_validator.py +812 -0
- runbooks/base.py +7 -0
- runbooks/cfat/assessment/compliance.py +1 -1
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cli/__init__.py +1 -1
- runbooks/cli/commands/cfat.py +64 -23
- runbooks/cli/commands/finops.py +1005 -54
- runbooks/cli/commands/inventory.py +138 -35
- runbooks/cli/commands/operate.py +9 -36
- runbooks/cli/commands/security.py +42 -18
- runbooks/cli/commands/validation.py +432 -18
- runbooks/cli/commands/vpc.py +81 -17
- runbooks/cli/registry.py +22 -10
- runbooks/cloudops/__init__.py +20 -27
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +544 -542
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +224 -225
- runbooks/cloudops/lifecycle_manager.py +5 -4
- runbooks/cloudops/mcp_cost_validation.py +252 -235
- runbooks/cloudops/models.py +78 -53
- runbooks/cloudops/monitoring_automation.py +5 -4
- runbooks/cloudops/notebook_framework.py +177 -213
- runbooks/cloudops/security_enforcer.py +125 -159
- runbooks/common/accuracy_validator.py +11 -0
- runbooks/common/aws_pricing.py +349 -326
- runbooks/common/aws_pricing_api.py +211 -212
- runbooks/common/aws_profile_manager.py +40 -36
- runbooks/common/aws_utils.py +74 -79
- runbooks/common/business_logic.py +126 -104
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
- runbooks/common/cross_account_manager.py +197 -204
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +29 -19
- runbooks/common/dry_run_examples.py +173 -208
- runbooks/common/dry_run_framework.py +157 -155
- runbooks/common/enhanced_exception_handler.py +15 -4
- runbooks/common/enhanced_logging_example.py +50 -64
- runbooks/common/enhanced_logging_integration_example.py +65 -37
- runbooks/common/env_utils.py +16 -16
- runbooks/common/error_handling.py +40 -38
- runbooks/common/lazy_loader.py +41 -23
- runbooks/common/logging_integration_helper.py +79 -86
- runbooks/common/mcp_cost_explorer_integration.py +476 -493
- runbooks/common/mcp_integration.py +63 -74
- runbooks/common/memory_optimization.py +140 -118
- runbooks/common/module_cli_base.py +37 -58
- runbooks/common/organizations_client.py +175 -193
- runbooks/common/patterns.py +23 -25
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +111 -37
- runbooks/common/rich_utils.py +201 -141
- runbooks/common/sre_performance_suite.py +177 -186
- runbooks/enterprise/__init__.py +1 -1
- runbooks/enterprise/logging.py +144 -106
- runbooks/enterprise/security.py +187 -204
- runbooks/enterprise/validation.py +43 -56
- runbooks/finops/__init__.py +26 -30
- runbooks/finops/account_resolver.py +1 -1
- runbooks/finops/advanced_optimization_engine.py +980 -0
- runbooks/finops/automation_core.py +268 -231
- runbooks/finops/business_case_config.py +184 -179
- runbooks/finops/cli.py +660 -139
- runbooks/finops/commvault_ec2_analysis.py +157 -164
- runbooks/finops/compute_cost_optimizer.py +336 -320
- runbooks/finops/config.py +20 -20
- runbooks/finops/cost_optimizer.py +484 -618
- runbooks/finops/cost_processor.py +332 -214
- runbooks/finops/dashboard_runner.py +1006 -172
- runbooks/finops/ebs_cost_optimizer.py +991 -657
- runbooks/finops/elastic_ip_optimizer.py +317 -257
- runbooks/finops/enhanced_mcp_integration.py +340 -0
- runbooks/finops/enhanced_progress.py +32 -29
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +223 -285
- runbooks/finops/executive_export.py +203 -160
- runbooks/finops/helpers.py +130 -288
- runbooks/finops/iam_guidance.py +1 -1
- runbooks/finops/infrastructure/__init__.py +80 -0
- runbooks/finops/infrastructure/commands.py +506 -0
- runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
- runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
- runbooks/finops/markdown_exporter.py +337 -174
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1512 -481
- runbooks/finops/network_cost_optimizer.py +657 -587
- runbooks/finops/notebook_utils.py +226 -188
- runbooks/finops/optimization_engine.py +1136 -0
- runbooks/finops/optimizer.py +19 -23
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +64 -65
- runbooks/finops/scenarios.py +1277 -438
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +259 -265
- runbooks/finops/vpc_cleanup_exporter.py +189 -144
- runbooks/finops/vpc_cleanup_optimizer.py +591 -573
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +1 -1
- runbooks/inventory/collectors/aws_networking.py +109 -99
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/inventory_mcp_cli.py +48 -46
- runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
- runbooks/inventory/mcp_inventory_validator.py +549 -465
- runbooks/inventory/mcp_vpc_validator.py +359 -442
- runbooks/inventory/organizations_discovery.py +55 -51
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +732 -695
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +1 -1
- runbooks/main.py +49 -34
- runbooks/main_final.py +91 -60
- runbooks/main_minimal.py +22 -10
- runbooks/main_optimized.py +131 -100
- runbooks/main_ultra_minimal.py +7 -2
- runbooks/mcp/__init__.py +36 -0
- runbooks/mcp/integration.py +679 -0
- runbooks/monitoring/performance_monitor.py +9 -4
- runbooks/operate/dynamodb_operations.py +3 -1
- runbooks/operate/ec2_operations.py +145 -137
- runbooks/operate/iam_operations.py +146 -152
- runbooks/operate/networking_cost_heatmap.py +29 -8
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_operations.py +646 -616
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +70 -66
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +86 -60
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +46 -41
- runbooks/security/__init__.py +19 -0
- runbooks/security/assessment_runner.py +1150 -0
- runbooks/security/baseline_checker.py +812 -0
- runbooks/security/cloudops_automation_security_validator.py +509 -535
- runbooks/security/compliance_automation_engine.py +17 -17
- runbooks/security/config/__init__.py +2 -2
- runbooks/security/config/compliance_config.py +50 -50
- runbooks/security/config_template_generator.py +63 -76
- runbooks/security/enterprise_security_framework.py +1 -1
- runbooks/security/executive_security_dashboard.py +519 -508
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/security_baseline_tester.py +1 -1
- runbooks/security/security_cli.py +143 -112
- runbooks/security/test_2way_validation.py +439 -0
- runbooks/security/two_way_validation_framework.py +852 -0
- runbooks/sre/production_monitoring_framework.py +167 -177
- runbooks/tdd/__init__.py +15 -0
- runbooks/tdd/cli.py +1071 -0
- runbooks/utils/__init__.py +14 -17
- runbooks/utils/logger.py +7 -2
- runbooks/utils/version_validator.py +50 -47
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +745 -704
- runbooks/validation/mcp_validator.py +906 -228
- runbooks/validation/terraform_citations_validator.py +104 -115
- runbooks/validation/terraform_drift_detector.py +447 -451
- runbooks/vpc/README.md +617 -0
- runbooks/vpc/__init__.py +8 -1
- runbooks/vpc/analyzer.py +577 -0
- runbooks/vpc/cleanup_wrapper.py +476 -413
- runbooks/vpc/cli_cloudtrail_commands.py +339 -0
- runbooks/vpc/cli_mcp_validation_commands.py +480 -0
- runbooks/vpc/cloudtrail_audit_integration.py +717 -0
- runbooks/vpc/config.py +92 -97
- runbooks/vpc/cost_engine.py +411 -148
- runbooks/vpc/cost_explorer_integration.py +553 -0
- runbooks/vpc/cross_account_session.py +101 -106
- runbooks/vpc/enhanced_mcp_validation.py +917 -0
- runbooks/vpc/eni_gate_validator.py +961 -0
- runbooks/vpc/heatmap_engine.py +185 -160
- runbooks/vpc/mcp_no_eni_validator.py +680 -639
- runbooks/vpc/nat_gateway_optimizer.py +358 -0
- runbooks/vpc/networking_wrapper.py +15 -8
- runbooks/vpc/pdca_remediation_planner.py +528 -0
- runbooks/vpc/performance_optimized_analyzer.py +219 -231
- runbooks/vpc/runbooks_adapter.py +1167 -241
- runbooks/vpc/tdd_red_phase_stubs.py +601 -0
- runbooks/vpc/test_data_loader.py +358 -0
- runbooks/vpc/tests/conftest.py +314 -4
- runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
- runbooks/vpc/tests/test_cost_engine.py +0 -2
- runbooks/vpc/topology_generator.py +326 -0
- runbooks/vpc/unified_scenarios.py +1297 -1124
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.4.dist-info ā runbooks-1.1.5.dist-info}/RECORD +214 -193
- runbooks/finops/README.md +0 -414
- runbooks/finops/accuracy_cross_validator.py +0 -647
- runbooks/finops/business_cases.py +0 -950
- runbooks/finops/dashboard_router.py +0 -922
- runbooks/finops/ebs_optimizer.py +0 -973
- runbooks/finops/embedded_mcp_validator.py +0 -1629
- runbooks/finops/enhanced_dashboard_runner.py +0 -527
- runbooks/finops/finops_dashboard.py +0 -584
- runbooks/finops/finops_scenarios.py +0 -1218
- runbooks/finops/legacy_migration.py +0 -730
- runbooks/finops/multi_dashboard.py +0 -1519
- runbooks/finops/single_dashboard.py +0 -1113
- runbooks/finops/unlimited_scenarios.py +0 -393
- runbooks-1.1.4.dist-info/METADATA +0 -800
- {runbooks-1.1.4.dist-info ā runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.4.dist-info ā runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.4.dist-info ā runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.4.dist-info ā runbooks-1.1.5.dist-info}/top_level.txt +0 -0
@@ -12,7 +12,7 @@ assessment across multi-account AWS Organizations.
|
|
12
12
|
|
13
13
|
**Architecture Focus**:
|
14
14
|
- Multi-account Landing Zone architecture validation
|
15
|
-
- AWS Well-Architected Framework compliance
|
15
|
+
- AWS Well-Architected Framework compliance
|
16
16
|
- Network topology impact assessment
|
17
17
|
- CIS Benchmark compliance validation
|
18
18
|
- Cross-account dependency analysis
|
@@ -20,7 +20,7 @@ assessment across multi-account AWS Organizations.
|
|
20
20
|
|
21
21
|
**Compliance Frameworks**:
|
22
22
|
- CIS AWS Foundations Benchmark
|
23
|
-
- AWS Well-Architected Security Pillar
|
23
|
+
- AWS Well-Architected Security Pillar
|
24
24
|
- SOC2 Type II compliance requirements
|
25
25
|
- Enterprise network governance standards
|
26
26
|
|
@@ -37,8 +37,14 @@ import boto3
|
|
37
37
|
from botocore.exceptions import ClientError
|
38
38
|
|
39
39
|
from runbooks.common.rich_utils import (
|
40
|
-
console,
|
41
|
-
|
40
|
+
console,
|
41
|
+
print_header,
|
42
|
+
print_success,
|
43
|
+
print_error,
|
44
|
+
print_warning,
|
45
|
+
create_table,
|
46
|
+
create_progress_bar,
|
47
|
+
STATUS_INDICATORS,
|
42
48
|
)
|
43
49
|
|
44
50
|
logger = logging.getLogger(__name__)
|
@@ -47,7 +53,7 @@ logger = logging.getLogger(__name__)
|
|
47
53
|
@dataclass
|
48
54
|
class ArchitectureComplianceResult:
|
49
55
|
"""Architecture compliance validation result."""
|
50
|
-
|
56
|
+
|
51
57
|
framework: str # CIS, Well-Architected, SOC2, etc.
|
52
58
|
control_id: str
|
53
59
|
control_description: str
|
@@ -61,246 +67,230 @@ class ArchitectureComplianceResult:
|
|
61
67
|
@dataclass
|
62
68
|
class AWSO5ArchitectureValidationResult:
|
63
69
|
"""Comprehensive AWSO-5 architecture validation result."""
|
64
|
-
|
70
|
+
|
65
71
|
vpc_id: str
|
66
72
|
account_id: str
|
67
73
|
region: str
|
68
|
-
|
74
|
+
|
69
75
|
# Architecture assessments
|
70
76
|
well_architected_score: Dict[str, float] = field(default_factory=dict)
|
71
77
|
cis_benchmark_compliance: Dict[str, str] = field(default_factory=dict)
|
72
78
|
security_posture_score: float = 0.0
|
73
79
|
network_impact_assessment: Dict[str, Any] = field(default_factory=dict)
|
74
|
-
|
80
|
+
|
75
81
|
# Compliance results
|
76
82
|
compliance_results: List[ArchitectureComplianceResult] = field(default_factory=list)
|
77
83
|
critical_findings: List[str] = field(default_factory=list)
|
78
84
|
security_improvements: List[str] = field(default_factory=list)
|
79
|
-
|
85
|
+
|
80
86
|
# Business impact
|
81
87
|
architecture_recommendation: str = "HOLD" # DELETE, DELETE_WITH_REMEDIATION, HOLD, INVESTIGATE
|
82
88
|
business_risk_level: str = "MEDIUM" # LOW, MEDIUM, HIGH, CRITICAL
|
83
89
|
estimated_security_improvement: float = 0.0
|
84
|
-
|
90
|
+
|
85
91
|
# Analysis metadata
|
86
92
|
validation_timestamp: str = field(default_factory=lambda: datetime.utcnow().isoformat())
|
87
93
|
validation_duration_seconds: float = 0.0
|
88
94
|
validation_accuracy: float = 100.0
|
89
|
-
|
95
|
+
|
90
96
|
@property
|
91
97
|
def overall_compliance_score(self) -> float:
|
92
98
|
"""Calculate overall compliance score from all frameworks."""
|
93
99
|
if not self.compliance_results:
|
94
100
|
return 0.0
|
95
|
-
|
101
|
+
|
96
102
|
total_weight = 0
|
97
103
|
weighted_score = 0
|
98
|
-
|
104
|
+
|
99
105
|
for result in self.compliance_results:
|
100
106
|
weight = self._get_control_weight(result.framework, result.impact_level)
|
101
107
|
total_weight += weight
|
102
|
-
|
108
|
+
|
103
109
|
if result.compliance_status == "PASS":
|
104
110
|
weighted_score += weight * 1.0
|
105
111
|
elif result.compliance_status == "WARNING":
|
106
112
|
weighted_score += weight * 0.5
|
107
113
|
# FAIL and NOT_APPLICABLE contribute 0
|
108
|
-
|
114
|
+
|
109
115
|
return (weighted_score / total_weight * 100) if total_weight > 0 else 0.0
|
110
|
-
|
116
|
+
|
111
117
|
def _get_control_weight(self, framework: str, impact_level: str) -> float:
|
112
118
|
"""Get weight for compliance control based on framework and impact."""
|
113
|
-
framework_weights = {
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
'Enterprise': 1.5
|
118
|
-
}
|
119
|
-
|
120
|
-
impact_multipliers = {
|
121
|
-
'CRITICAL': 4.0,
|
122
|
-
'HIGH': 3.0,
|
123
|
-
'MEDIUM': 2.0,
|
124
|
-
'LOW': 1.0
|
125
|
-
}
|
126
|
-
|
119
|
+
framework_weights = {"CIS": 3.0, "Well-Architected": 2.5, "SOC2": 2.0, "Enterprise": 1.5}
|
120
|
+
|
121
|
+
impact_multipliers = {"CRITICAL": 4.0, "HIGH": 3.0, "MEDIUM": 2.0, "LOW": 1.0}
|
122
|
+
|
127
123
|
base_weight = framework_weights.get(framework, 1.0)
|
128
124
|
multiplier = impact_multipliers.get(impact_level, 1.0)
|
129
|
-
|
125
|
+
|
130
126
|
return base_weight * multiplier
|
131
127
|
|
132
128
|
|
133
129
|
class AWSO5ArchitectureValidator:
|
134
130
|
"""
|
135
131
|
AWSO-5 Multi-Account Architecture Validator.
|
136
|
-
|
132
|
+
|
137
133
|
Comprehensive architecture validation for VPC cleanup with enterprise
|
138
134
|
compliance checking, security posture assessment, and business risk analysis.
|
139
|
-
|
135
|
+
|
140
136
|
**Enterprise Integration**:
|
141
137
|
- Multi-account AWS Organizations support
|
142
138
|
- Well-Architected Framework assessment
|
143
|
-
- CIS Benchmark compliance validation
|
139
|
+
- CIS Benchmark compliance validation
|
144
140
|
- Cross-account dependency analysis
|
145
141
|
- Security baseline enforcement
|
146
142
|
- Network topology impact assessment
|
147
143
|
"""
|
148
|
-
|
144
|
+
|
149
145
|
def __init__(self, session: Optional[boto3.Session] = None, region: str = "us-east-1"):
|
150
146
|
"""Initialize AWSO-5 architecture validator."""
|
151
147
|
self.session = session or boto3.Session()
|
152
148
|
self.region = region
|
153
149
|
self.console = console
|
154
|
-
|
150
|
+
|
155
151
|
# Initialize AWS clients
|
156
152
|
self._ec2_client = None
|
157
153
|
self._organizations_client = None
|
158
154
|
self._config_client = None
|
159
155
|
self._cloudtrail_client = None
|
160
|
-
|
156
|
+
|
161
157
|
# Validation tracking
|
162
158
|
self.validation_results: Dict[str, AWSO5ArchitectureValidationResult] = {}
|
163
|
-
|
159
|
+
|
164
160
|
@property
|
165
161
|
def ec2_client(self):
|
166
162
|
"""Lazy-loaded EC2 client."""
|
167
163
|
if not self._ec2_client:
|
168
|
-
self._ec2_client = self.session.client(
|
164
|
+
self._ec2_client = self.session.client("ec2", region_name=self.region)
|
169
165
|
return self._ec2_client
|
170
|
-
|
166
|
+
|
171
167
|
@property
|
172
168
|
def organizations_client(self):
|
173
169
|
"""Lazy-loaded Organizations client."""
|
174
170
|
if not self._organizations_client:
|
175
|
-
self._organizations_client = self.session.client(
|
171
|
+
self._organizations_client = self.session.client("organizations", region_name="us-east-1")
|
176
172
|
return self._organizations_client
|
177
|
-
|
173
|
+
|
178
174
|
@property
|
179
175
|
def config_client(self):
|
180
176
|
"""Lazy-loaded Config client."""
|
181
177
|
if not self._config_client:
|
182
|
-
self._config_client = self.session.client(
|
178
|
+
self._config_client = self.session.client("config", region_name=self.region)
|
183
179
|
return self._config_client
|
184
|
-
|
180
|
+
|
185
181
|
@property
|
186
182
|
def cloudtrail_client(self):
|
187
183
|
"""Lazy-loaded CloudTrail client."""
|
188
184
|
if not self._cloudtrail_client:
|
189
|
-
self._cloudtrail_client = self.session.client(
|
185
|
+
self._cloudtrail_client = self.session.client("cloudtrail", region_name=self.region)
|
190
186
|
return self._cloudtrail_client
|
191
|
-
|
187
|
+
|
192
188
|
def validate_vpc_architecture(self, vpc_id: str) -> AWSO5ArchitectureValidationResult:
|
193
189
|
"""
|
194
190
|
Comprehensive VPC architecture validation for AWSO-5 compliance.
|
195
|
-
|
191
|
+
|
196
192
|
Performs multi-dimensional architecture assessment including security
|
197
193
|
posture, compliance frameworks, network impact, and business risk analysis.
|
198
|
-
|
194
|
+
|
199
195
|
Args:
|
200
196
|
vpc_id: AWS VPC identifier to validate
|
201
|
-
|
197
|
+
|
202
198
|
Returns:
|
203
199
|
Comprehensive architecture validation results
|
204
200
|
"""
|
205
201
|
start_time = datetime.utcnow()
|
206
|
-
|
202
|
+
|
207
203
|
# Get VPC and account information
|
208
204
|
vpc_info = self._get_vpc_info(vpc_id)
|
209
205
|
if not vpc_info:
|
210
206
|
raise ValueError(f"VPC {vpc_id} not found in region {self.region}")
|
211
|
-
|
212
|
-
account_id = self.session.client(
|
213
|
-
|
214
|
-
result = AWSO5ArchitectureValidationResult(
|
215
|
-
|
216
|
-
account_id=account_id,
|
217
|
-
region=self.region
|
218
|
-
)
|
219
|
-
|
207
|
+
|
208
|
+
account_id = self.session.client("sts").get_caller_identity()["Account"]
|
209
|
+
|
210
|
+
result = AWSO5ArchitectureValidationResult(vpc_id=vpc_id, account_id=account_id, region=self.region)
|
211
|
+
|
220
212
|
print_header("AWSO-5 Architecture Validation", "1.0.0")
|
221
213
|
self.console.print(f"\n[blue]VPC Architecture Analysis:[/blue] {vpc_id}")
|
222
214
|
self.console.print(f"[blue]Account:[/blue] {account_id}")
|
223
215
|
self.console.print(f"[blue]Region:[/blue] {self.region}")
|
224
|
-
|
216
|
+
|
225
217
|
# Validation phases
|
226
218
|
self.console.print("\n[yellow]Phase 1: CIS Benchmark Compliance[/yellow]")
|
227
219
|
self._validate_cis_benchmark_compliance(vpc_id, vpc_info, result)
|
228
|
-
|
229
|
-
self.console.print("\n[yellow]Phase 2: AWS Well-Architected Assessment[/yellow]")
|
220
|
+
|
221
|
+
self.console.print("\n[yellow]Phase 2: AWS Well-Architected Assessment[/yellow]")
|
230
222
|
self._validate_well_architected_framework(vpc_id, vpc_info, result)
|
231
|
-
|
223
|
+
|
232
224
|
self.console.print("\n[yellow]Phase 3: Security Posture Analysis[/yellow]")
|
233
225
|
self._analyze_security_posture(vpc_id, vpc_info, result)
|
234
|
-
|
226
|
+
|
235
227
|
self.console.print("\n[yellow]Phase 4: Network Impact Assessment[/yellow]")
|
236
228
|
self._assess_network_impact(vpc_id, vpc_info, result)
|
237
|
-
|
229
|
+
|
238
230
|
self.console.print("\n[yellow]Phase 5: Business Risk Analysis[/yellow]")
|
239
231
|
self._analyze_business_risk(vpc_id, vpc_info, result)
|
240
|
-
|
232
|
+
|
241
233
|
# Calculate final metrics
|
242
234
|
end_time = datetime.utcnow()
|
243
235
|
result.validation_duration_seconds = (end_time - start_time).total_seconds()
|
244
236
|
result.security_posture_score = self._calculate_security_posture_score(result)
|
245
|
-
|
237
|
+
|
246
238
|
# Generate architecture recommendation
|
247
239
|
self._generate_architecture_recommendation(result)
|
248
|
-
|
240
|
+
|
249
241
|
# Store results for evidence collection
|
250
242
|
self.validation_results[vpc_id] = result
|
251
|
-
|
243
|
+
|
252
244
|
# Display comprehensive results
|
253
245
|
self._display_validation_results(result)
|
254
|
-
|
246
|
+
|
255
247
|
return result
|
256
|
-
|
248
|
+
|
257
249
|
def _get_vpc_info(self, vpc_id: str) -> Optional[Dict[str, Any]]:
|
258
250
|
"""Get comprehensive VPC information."""
|
259
251
|
try:
|
260
252
|
response = self.ec2_client.describe_vpcs(VpcIds=[vpc_id])
|
261
|
-
return response[
|
253
|
+
return response["Vpcs"][0] if response["Vpcs"] else None
|
262
254
|
except ClientError as e:
|
263
255
|
print_error(f"Failed to get VPC info: {e}")
|
264
256
|
return None
|
265
|
-
|
257
|
+
|
266
258
|
def _validate_cis_benchmark_compliance(
|
267
|
-
self,
|
268
|
-
vpc_id: str,
|
269
|
-
vpc_info: Dict[str, Any],
|
270
|
-
result: AWSO5ArchitectureValidationResult
|
259
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
271
260
|
):
|
272
261
|
"""Validate CIS AWS Foundations Benchmark compliance."""
|
273
|
-
|
262
|
+
|
274
263
|
# CIS Control 4.1: Ensure no security groups allow ingress from 0.0.0.0/0 to port 22
|
275
264
|
self._check_cis_4_1_ssh_access(vpc_id, result)
|
276
|
-
|
277
|
-
# CIS Control 4.2: Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389
|
265
|
+
|
266
|
+
# CIS Control 4.2: Ensure no security groups allow ingress from 0.0.0.0/0 to port 3389
|
278
267
|
self._check_cis_4_2_rdp_access(vpc_id, result)
|
279
|
-
|
268
|
+
|
280
269
|
# CIS Control 4.3: Ensure the default security group restricts all traffic
|
281
270
|
self._check_cis_4_3_default_security_group(vpc_id, result)
|
282
|
-
|
271
|
+
|
283
272
|
# CIS Control 2.6: Ensure VPC flow logging is enabled
|
284
273
|
self._check_cis_2_6_vpc_flow_logging(vpc_id, result)
|
285
|
-
|
274
|
+
|
286
275
|
# Default VPC specific checks
|
287
|
-
if vpc_info.get(
|
276
|
+
if vpc_info.get("IsDefault", False):
|
288
277
|
self._check_default_vpc_compliance(vpc_id, vpc_info, result)
|
289
|
-
|
278
|
+
|
290
279
|
def _check_cis_4_1_ssh_access(self, vpc_id: str, result: AWSO5ArchitectureValidationResult):
|
291
280
|
"""Check CIS 4.1: SSH access from 0.0.0.0/0."""
|
292
281
|
try:
|
293
|
-
response = self.ec2_client.describe_security_groups(
|
294
|
-
|
295
|
-
)
|
296
|
-
|
282
|
+
response = self.ec2_client.describe_security_groups(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
|
283
|
+
|
297
284
|
violations = []
|
298
|
-
for sg in response[
|
299
|
-
for rule in sg.get(
|
300
|
-
if (
|
301
|
-
|
285
|
+
for sg in response["SecurityGroups"]:
|
286
|
+
for rule in sg.get("IpPermissions", []):
|
287
|
+
if (
|
288
|
+
rule.get("FromPort") == 22
|
289
|
+
and rule.get("ToPort") == 22
|
290
|
+
and any(ip_range.get("CidrIp") == "0.0.0.0/0" for ip_range in rule.get("IpRanges", []))
|
291
|
+
):
|
302
292
|
violations.append(f"Security Group {sg['GroupId']} ({sg['GroupName']})")
|
303
|
-
|
293
|
+
|
304
294
|
if violations:
|
305
295
|
compliance_result = ArchitectureComplianceResult(
|
306
296
|
framework="CIS",
|
@@ -309,7 +299,7 @@ class AWSO5ArchitectureValidator:
|
|
309
299
|
compliance_status="FAIL",
|
310
300
|
impact_level="HIGH",
|
311
301
|
findings=violations,
|
312
|
-
remediation_guidance="Restrict SSH access to specific IP ranges"
|
302
|
+
remediation_guidance="Restrict SSH access to specific IP ranges",
|
313
303
|
)
|
314
304
|
result.critical_findings.extend(violations)
|
315
305
|
else:
|
@@ -318,29 +308,30 @@ class AWSO5ArchitectureValidator:
|
|
318
308
|
control_id="4.1",
|
319
309
|
control_description="No security groups allow ingress from 0.0.0.0/0 to port 22",
|
320
310
|
compliance_status="PASS",
|
321
|
-
impact_level="HIGH"
|
311
|
+
impact_level="HIGH",
|
322
312
|
)
|
323
|
-
|
313
|
+
|
324
314
|
result.compliance_results.append(compliance_result)
|
325
315
|
result.cis_benchmark_compliance["4.1"] = compliance_result.compliance_status
|
326
|
-
|
316
|
+
|
327
317
|
except ClientError as e:
|
328
318
|
print_warning(f"CIS 4.1 check failed: {e}")
|
329
|
-
|
319
|
+
|
330
320
|
def _check_cis_4_2_rdp_access(self, vpc_id: str, result: AWSO5ArchitectureValidationResult):
|
331
321
|
"""Check CIS 4.2: RDP access from 0.0.0.0/0."""
|
332
322
|
try:
|
333
|
-
response = self.ec2_client.describe_security_groups(
|
334
|
-
|
335
|
-
)
|
336
|
-
|
323
|
+
response = self.ec2_client.describe_security_groups(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
|
324
|
+
|
337
325
|
violations = []
|
338
|
-
for sg in response[
|
339
|
-
for rule in sg.get(
|
340
|
-
if (
|
341
|
-
|
326
|
+
for sg in response["SecurityGroups"]:
|
327
|
+
for rule in sg.get("IpPermissions", []):
|
328
|
+
if (
|
329
|
+
rule.get("FromPort") == 3389
|
330
|
+
and rule.get("ToPort") == 3389
|
331
|
+
and any(ip_range.get("CidrIp") == "0.0.0.0/0" for ip_range in rule.get("IpRanges", []))
|
332
|
+
):
|
342
333
|
violations.append(f"Security Group {sg['GroupId']} ({sg['GroupName']})")
|
343
|
-
|
334
|
+
|
344
335
|
if violations:
|
345
336
|
compliance_result = ArchitectureComplianceResult(
|
346
337
|
framework="CIS",
|
@@ -349,49 +340,46 @@ class AWSO5ArchitectureValidator:
|
|
349
340
|
compliance_status="FAIL",
|
350
341
|
impact_level="HIGH",
|
351
342
|
findings=violations,
|
352
|
-
remediation_guidance="Restrict RDP access to specific IP ranges"
|
343
|
+
remediation_guidance="Restrict RDP access to specific IP ranges",
|
353
344
|
)
|
354
345
|
result.critical_findings.extend(violations)
|
355
346
|
else:
|
356
347
|
compliance_result = ArchitectureComplianceResult(
|
357
348
|
framework="CIS",
|
358
|
-
control_id="4.2",
|
349
|
+
control_id="4.2",
|
359
350
|
control_description="No security groups allow ingress from 0.0.0.0/0 to port 3389",
|
360
351
|
compliance_status="PASS",
|
361
|
-
impact_level="HIGH"
|
352
|
+
impact_level="HIGH",
|
362
353
|
)
|
363
|
-
|
354
|
+
|
364
355
|
result.compliance_results.append(compliance_result)
|
365
356
|
result.cis_benchmark_compliance["4.2"] = compliance_result.compliance_status
|
366
|
-
|
357
|
+
|
367
358
|
except ClientError as e:
|
368
359
|
print_warning(f"CIS 4.2 check failed: {e}")
|
369
|
-
|
360
|
+
|
370
361
|
def _check_cis_4_3_default_security_group(self, vpc_id: str, result: AWSO5ArchitectureValidationResult):
|
371
362
|
"""Check CIS 4.3: Default security group restrictions."""
|
372
363
|
try:
|
373
364
|
response = self.ec2_client.describe_security_groups(
|
374
|
-
Filters=[
|
375
|
-
{'Name': 'vpc-id', 'Values': [vpc_id]},
|
376
|
-
{'Name': 'group-name', 'Values': ['default']}
|
377
|
-
]
|
365
|
+
Filters=[{"Name": "vpc-id", "Values": [vpc_id]}, {"Name": "group-name", "Values": ["default"]}]
|
378
366
|
)
|
379
|
-
|
367
|
+
|
380
368
|
violations = []
|
381
|
-
for sg in response[
|
382
|
-
if sg.get(
|
369
|
+
for sg in response["SecurityGroups"]:
|
370
|
+
if sg.get("IpPermissions") or sg.get("IpPermissionsEgress"):
|
383
371
|
# Default SG should have no rules
|
384
372
|
violations.append(f"Default Security Group {sg['GroupId']} has active rules")
|
385
|
-
|
373
|
+
|
386
374
|
if violations:
|
387
375
|
compliance_result = ArchitectureComplianceResult(
|
388
376
|
framework="CIS",
|
389
377
|
control_id="4.3",
|
390
378
|
control_description="Default security group restricts all traffic",
|
391
|
-
compliance_status="FAIL",
|
379
|
+
compliance_status="FAIL",
|
392
380
|
impact_level="MEDIUM",
|
393
381
|
findings=violations,
|
394
|
-
remediation_guidance="Remove all rules from default security group"
|
382
|
+
remediation_guidance="Remove all rules from default security group",
|
395
383
|
)
|
396
384
|
else:
|
397
385
|
compliance_result = ArchitectureComplianceResult(
|
@@ -399,30 +387,24 @@ class AWSO5ArchitectureValidator:
|
|
399
387
|
control_id="4.3",
|
400
388
|
control_description="Default security group restricts all traffic",
|
401
389
|
compliance_status="PASS",
|
402
|
-
impact_level="MEDIUM"
|
390
|
+
impact_level="MEDIUM",
|
403
391
|
)
|
404
|
-
|
392
|
+
|
405
393
|
result.compliance_results.append(compliance_result)
|
406
394
|
result.cis_benchmark_compliance["4.3"] = compliance_result.compliance_status
|
407
|
-
|
395
|
+
|
408
396
|
except ClientError as e:
|
409
397
|
print_warning(f"CIS 4.3 check failed: {e}")
|
410
|
-
|
398
|
+
|
411
399
|
def _check_cis_2_6_vpc_flow_logging(self, vpc_id: str, result: AWSO5ArchitectureValidationResult):
|
412
400
|
"""Check CIS 2.6: VPC Flow Logs enabled."""
|
413
401
|
try:
|
414
402
|
response = self.ec2_client.describe_flow_logs(
|
415
|
-
Filters=[
|
416
|
-
{'Name': 'resource-id', 'Values': [vpc_id]},
|
417
|
-
{'Name': 'resource-type', 'Values': ['VPC']}
|
418
|
-
]
|
403
|
+
Filters=[{"Name": "resource-id", "Values": [vpc_id]}, {"Name": "resource-type", "Values": ["VPC"]}]
|
419
404
|
)
|
420
|
-
|
421
|
-
active_flow_logs = [
|
422
|
-
|
423
|
-
if fl['FlowLogStatus'] == 'ACTIVE'
|
424
|
-
]
|
425
|
-
|
405
|
+
|
406
|
+
active_flow_logs = [fl for fl in response["FlowLogs"] if fl["FlowLogStatus"] == "ACTIVE"]
|
407
|
+
|
426
408
|
if not active_flow_logs:
|
427
409
|
compliance_result = ArchitectureComplianceResult(
|
428
410
|
framework="CIS",
|
@@ -431,7 +413,7 @@ class AWSO5ArchitectureValidator:
|
|
431
413
|
compliance_status="FAIL",
|
432
414
|
impact_level="MEDIUM",
|
433
415
|
findings=[f"VPC {vpc_id} has no active flow logs"],
|
434
|
-
remediation_guidance="Enable VPC Flow Logs for security monitoring"
|
416
|
+
remediation_guidance="Enable VPC Flow Logs for security monitoring",
|
435
417
|
)
|
436
418
|
else:
|
437
419
|
compliance_result = ArchitectureComplianceResult(
|
@@ -439,23 +421,20 @@ class AWSO5ArchitectureValidator:
|
|
439
421
|
control_id="2.6",
|
440
422
|
control_description="VPC Flow Logging is enabled",
|
441
423
|
compliance_status="PASS",
|
442
|
-
impact_level="MEDIUM"
|
424
|
+
impact_level="MEDIUM",
|
443
425
|
)
|
444
|
-
|
426
|
+
|
445
427
|
result.compliance_results.append(compliance_result)
|
446
428
|
result.cis_benchmark_compliance["2.6"] = compliance_result.compliance_status
|
447
|
-
|
429
|
+
|
448
430
|
except ClientError as e:
|
449
431
|
print_warning(f"CIS 2.6 check failed: {e}")
|
450
|
-
|
432
|
+
|
451
433
|
def _check_default_vpc_compliance(
|
452
|
-
self,
|
453
|
-
vpc_id: str,
|
454
|
-
vpc_info: Dict[str, Any],
|
455
|
-
result: AWSO5ArchitectureValidationResult
|
434
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
456
435
|
):
|
457
436
|
"""Special compliance checks for default VPCs."""
|
458
|
-
|
437
|
+
|
459
438
|
# Default VPC should be deleted per CIS recommendations
|
460
439
|
compliance_result = ArchitectureComplianceResult(
|
461
440
|
framework="CIS",
|
@@ -464,83 +443,77 @@ class AWSO5ArchitectureValidator:
|
|
464
443
|
compliance_status="FAIL",
|
465
444
|
impact_level="CRITICAL",
|
466
445
|
findings=[f"Default VPC {vpc_id} exists in region {self.region}"],
|
467
|
-
remediation_guidance="Delete default VPC to improve security posture and CIS compliance"
|
446
|
+
remediation_guidance="Delete default VPC to improve security posture and CIS compliance",
|
468
447
|
)
|
469
|
-
|
448
|
+
|
470
449
|
result.compliance_results.append(compliance_result)
|
471
450
|
result.cis_benchmark_compliance["DEFAULT_VPC"] = "FAIL"
|
472
451
|
result.critical_findings.append(f"Default VPC {vpc_id} requires deletion")
|
473
452
|
result.security_improvements.append("Default VPC elimination improves CIS Benchmark compliance")
|
474
|
-
|
453
|
+
|
475
454
|
def _validate_well_architected_framework(
|
476
|
-
self,
|
477
|
-
vpc_id: str,
|
478
|
-
vpc_info: Dict[str, Any],
|
479
|
-
result: AWSO5ArchitectureValidationResult
|
455
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
480
456
|
):
|
481
457
|
"""Validate against AWS Well-Architected Framework principles."""
|
482
|
-
|
458
|
+
|
483
459
|
# Security Pillar Assessment
|
484
460
|
security_score = self._assess_security_pillar(vpc_id, vpc_info, result)
|
485
461
|
result.well_architected_score["Security"] = security_score
|
486
|
-
|
462
|
+
|
487
463
|
# Reliability Pillar Assessment
|
488
464
|
reliability_score = self._assess_reliability_pillar(vpc_id, vpc_info, result)
|
489
465
|
result.well_architected_score["Reliability"] = reliability_score
|
490
|
-
|
491
|
-
# Performance Efficiency Assessment
|
466
|
+
|
467
|
+
# Performance Efficiency Assessment
|
492
468
|
performance_score = self._assess_performance_pillar(vpc_id, vpc_info, result)
|
493
469
|
result.well_architected_score["Performance"] = performance_score
|
494
|
-
|
470
|
+
|
495
471
|
# Cost Optimization Assessment
|
496
472
|
cost_score = self._assess_cost_pillar(vpc_id, vpc_info, result)
|
497
473
|
result.well_architected_score["Cost"] = cost_score
|
498
|
-
|
474
|
+
|
499
475
|
# Operational Excellence Assessment
|
500
476
|
ops_score = self._assess_operational_pillar(vpc_id, vpc_info, result)
|
501
477
|
result.well_architected_score["Operational"] = ops_score
|
502
|
-
|
478
|
+
|
503
479
|
def _assess_security_pillar(
|
504
|
-
self,
|
505
|
-
vpc_id: str,
|
506
|
-
vpc_info: Dict[str, Any],
|
507
|
-
result: AWSO5ArchitectureValidationResult
|
480
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
508
481
|
) -> float:
|
509
482
|
"""Assess Well-Architected Security Pillar."""
|
510
|
-
|
483
|
+
|
511
484
|
security_checks = []
|
512
|
-
|
485
|
+
|
513
486
|
# SEC-3: Apply security in depth principle
|
514
487
|
try:
|
515
488
|
# Check for NACLs and Security Groups
|
516
|
-
nacls = self.ec2_client.describe_network_acls(
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
sgs = self.ec2_client.describe_security_groups(
|
521
|
-
|
522
|
-
|
523
|
-
|
489
|
+
nacls = self.ec2_client.describe_network_acls(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])[
|
490
|
+
"NetworkAcls"
|
491
|
+
]
|
492
|
+
|
493
|
+
sgs = self.ec2_client.describe_security_groups(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])[
|
494
|
+
"SecurityGroups"
|
495
|
+
]
|
496
|
+
|
524
497
|
if len(nacls) > 1 or len(sgs) > 1: # More than just defaults
|
525
498
|
security_checks.append(("Defense in Depth", "PASS"))
|
526
499
|
else:
|
527
500
|
security_checks.append(("Defense in Depth", "FAIL"))
|
528
|
-
|
501
|
+
|
529
502
|
except ClientError:
|
530
503
|
security_checks.append(("Defense in Depth", "UNKNOWN"))
|
531
|
-
|
504
|
+
|
532
505
|
# SEC-9: Protect data in transit and at rest
|
533
|
-
if vpc_info.get(
|
506
|
+
if vpc_info.get("IsDefault", False):
|
534
507
|
security_checks.append(("Default VPC Security", "FAIL"))
|
535
508
|
result.security_improvements.append("Default VPC replacement improves data protection")
|
536
509
|
else:
|
537
510
|
security_checks.append(("Default VPC Security", "PASS"))
|
538
|
-
|
511
|
+
|
539
512
|
# Calculate security score
|
540
513
|
passed = len([check for check in security_checks if check[1] == "PASS"])
|
541
514
|
total = len(security_checks)
|
542
515
|
score = (passed / total * 100) if total > 0 else 0
|
543
|
-
|
516
|
+
|
544
517
|
# Add Well-Architected compliance result
|
545
518
|
compliance_result = ArchitectureComplianceResult(
|
546
519
|
framework="Well-Architected",
|
@@ -549,252 +522,221 @@ class AWSO5ArchitectureValidator:
|
|
549
522
|
compliance_status="PASS" if score >= 80 else "WARNING" if score >= 60 else "FAIL",
|
550
523
|
impact_level="HIGH",
|
551
524
|
findings=[f"Security score: {score:.1f}% ({passed}/{total} checks passed)"],
|
552
|
-
remediation_guidance="Implement defense in depth and eliminate default VPCs"
|
525
|
+
remediation_guidance="Implement defense in depth and eliminate default VPCs",
|
553
526
|
)
|
554
|
-
|
527
|
+
|
555
528
|
result.compliance_results.append(compliance_result)
|
556
|
-
|
529
|
+
|
557
530
|
return score
|
558
|
-
|
531
|
+
|
559
532
|
def _assess_reliability_pillar(
|
560
|
-
self,
|
561
|
-
vpc_id: str,
|
562
|
-
vpc_info: Dict[str, Any],
|
563
|
-
result: AWSO5ArchitectureValidationResult
|
533
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
564
534
|
) -> float:
|
565
535
|
"""Assess Well-Architected Reliability Pillar."""
|
566
|
-
|
536
|
+
|
567
537
|
reliability_checks = []
|
568
|
-
|
538
|
+
|
569
539
|
# REL-1: Multi-AZ deployment capability
|
570
540
|
try:
|
571
|
-
subnets = self.ec2_client.describe_subnets(
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
azs = set(subnet['AvailabilityZone'] for subnet in subnets)
|
541
|
+
subnets = self.ec2_client.describe_subnets(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])["Subnets"]
|
542
|
+
|
543
|
+
azs = set(subnet["AvailabilityZone"] for subnet in subnets)
|
576
544
|
if len(azs) >= 2:
|
577
545
|
reliability_checks.append(("Multi-AZ Support", "PASS"))
|
578
546
|
else:
|
579
547
|
reliability_checks.append(("Multi-AZ Support", "WARNING"))
|
580
|
-
|
548
|
+
|
581
549
|
except ClientError:
|
582
550
|
reliability_checks.append(("Multi-AZ Support", "UNKNOWN"))
|
583
|
-
|
551
|
+
|
584
552
|
# Calculate reliability score
|
585
553
|
passed = len([check for check in reliability_checks if check[1] == "PASS"])
|
586
|
-
total = len(reliability_checks)
|
554
|
+
total = len(reliability_checks)
|
587
555
|
score = (passed / total * 100) if total > 0 else 0
|
588
|
-
|
556
|
+
|
589
557
|
return score
|
590
|
-
|
558
|
+
|
591
559
|
def _assess_performance_pillar(
|
592
|
-
self,
|
593
|
-
vpc_id: str,
|
594
|
-
vpc_info: Dict[str, Any],
|
595
|
-
result: AWSO5ArchitectureValidationResult
|
560
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
596
561
|
) -> float:
|
597
562
|
"""Assess Well-Architected Performance Efficiency Pillar."""
|
598
|
-
|
563
|
+
|
599
564
|
performance_checks = []
|
600
|
-
|
565
|
+
|
601
566
|
# PERF-1: Network performance optimization
|
602
567
|
try:
|
603
568
|
# Check for VPC endpoints (reduce data transfer costs)
|
604
|
-
endpoints = self.ec2_client.describe_vpc_endpoints(
|
605
|
-
|
606
|
-
|
607
|
-
|
569
|
+
endpoints = self.ec2_client.describe_vpc_endpoints(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])[
|
570
|
+
"VpcEndpoints"
|
571
|
+
]
|
572
|
+
|
608
573
|
if endpoints:
|
609
574
|
performance_checks.append(("VPC Endpoints Optimization", "PASS"))
|
610
575
|
else:
|
611
576
|
performance_checks.append(("VPC Endpoints Optimization", "WARNING"))
|
612
|
-
|
577
|
+
|
613
578
|
except ClientError:
|
614
579
|
performance_checks.append(("VPC Endpoints Optimization", "UNKNOWN"))
|
615
|
-
|
580
|
+
|
616
581
|
# Calculate performance score
|
617
582
|
passed = len([check for check in performance_checks if check[1] == "PASS"])
|
618
583
|
total = len(performance_checks)
|
619
584
|
score = (passed / total * 100) if total > 0 else 50 # Neutral score if no checks
|
620
|
-
|
585
|
+
|
621
586
|
return score
|
622
|
-
|
587
|
+
|
623
588
|
def _assess_cost_pillar(
|
624
|
-
self,
|
625
|
-
vpc_id: str,
|
626
|
-
vpc_info: Dict[str, Any],
|
627
|
-
result: AWSO5ArchitectureValidationResult
|
589
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
628
590
|
) -> float:
|
629
591
|
"""Assess Well-Architected Cost Optimization Pillar."""
|
630
|
-
|
592
|
+
|
631
593
|
cost_checks = []
|
632
|
-
|
594
|
+
|
633
595
|
# COST-1: Unused resource identification
|
634
|
-
if vpc_info.get(
|
596
|
+
if vpc_info.get("IsDefault", False):
|
635
597
|
cost_checks.append(("Default VPC Cost Impact", "FAIL"))
|
636
598
|
result.estimated_security_improvement += 25.0 # Monthly savings estimate
|
637
599
|
else:
|
638
600
|
cost_checks.append(("Default VPC Cost Impact", "PASS"))
|
639
|
-
|
601
|
+
|
640
602
|
# Calculate cost score
|
641
603
|
passed = len([check for check in cost_checks if check[1] == "PASS"])
|
642
604
|
total = len(cost_checks)
|
643
605
|
score = (passed / total * 100) if total > 0 else 0
|
644
|
-
|
606
|
+
|
645
607
|
return score
|
646
|
-
|
608
|
+
|
647
609
|
def _assess_operational_pillar(
|
648
|
-
self,
|
649
|
-
vpc_id: str,
|
650
|
-
vpc_info: Dict[str, Any],
|
651
|
-
result: AWSO5ArchitectureValidationResult
|
610
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
652
611
|
) -> float:
|
653
612
|
"""Assess Well-Architected Operational Excellence Pillar."""
|
654
|
-
|
613
|
+
|
655
614
|
ops_checks = []
|
656
|
-
|
615
|
+
|
657
616
|
# OPS-1: Infrastructure as Code usage
|
658
617
|
# This would require additional analysis of CloudFormation/Terraform
|
659
618
|
ops_checks.append(("Infrastructure as Code", "UNKNOWN"))
|
660
|
-
|
619
|
+
|
661
620
|
# Calculate operational score
|
662
621
|
score = 50 # Neutral score - requires additional IaC analysis
|
663
|
-
|
622
|
+
|
664
623
|
return score
|
665
|
-
|
624
|
+
|
666
625
|
def _analyze_security_posture(
|
667
|
-
self,
|
668
|
-
vpc_id: str,
|
669
|
-
vpc_info: Dict[str, Any],
|
670
|
-
result: AWSO5ArchitectureValidationResult
|
626
|
+
self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult
|
671
627
|
):
|
672
628
|
"""Comprehensive security posture analysis."""
|
673
|
-
|
629
|
+
|
674
630
|
# Security baseline checks
|
675
631
|
security_findings = []
|
676
|
-
|
632
|
+
|
677
633
|
# Default VPC security impact
|
678
|
-
if vpc_info.get(
|
634
|
+
if vpc_info.get("IsDefault", False):
|
679
635
|
security_findings.append("Default VPC presents increased attack surface")
|
680
636
|
security_findings.append("Default security groups may have overly permissive rules")
|
681
637
|
security_findings.append("Default infrastructure lacks security hardening")
|
682
|
-
|
683
|
-
result.security_improvements.extend(
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
vpc_info: Dict[str, Any],
|
693
|
-
result: AWSO5ArchitectureValidationResult
|
694
|
-
):
|
638
|
+
|
639
|
+
result.security_improvements.extend(
|
640
|
+
[
|
641
|
+
"Default VPC elimination reduces attack surface by ~30%",
|
642
|
+
"Custom VPC implementation enables security best practices",
|
643
|
+
"Network segmentation improves compliance posture",
|
644
|
+
]
|
645
|
+
)
|
646
|
+
|
647
|
+
def _assess_network_impact(self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult):
|
695
648
|
"""Assess network topology impact of VPC cleanup."""
|
696
|
-
|
649
|
+
|
697
650
|
network_impact = {
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
651
|
+
"connectivity_impact": "NONE", # NONE, LOW, MEDIUM, HIGH
|
652
|
+
"routing_changes_required": False,
|
653
|
+
"cross_account_dependencies": [],
|
654
|
+
"transit_gateway_impact": False,
|
655
|
+
"peering_connections_affected": 0,
|
703
656
|
}
|
704
|
-
|
657
|
+
|
705
658
|
try:
|
706
659
|
# Check for transit gateway attachments
|
707
660
|
tgw_attachments = self.ec2_client.describe_transit_gateway_attachments(
|
708
|
-
Filters=[
|
709
|
-
|
710
|
-
|
711
|
-
]
|
712
|
-
)['TransitGatewayAttachments']
|
713
|
-
|
661
|
+
Filters=[{"Name": "resource-id", "Values": [vpc_id]}, {"Name": "resource-type", "Values": ["vpc"]}]
|
662
|
+
)["TransitGatewayAttachments"]
|
663
|
+
|
714
664
|
if tgw_attachments:
|
715
|
-
network_impact[
|
716
|
-
network_impact[
|
717
|
-
|
665
|
+
network_impact["transit_gateway_impact"] = True
|
666
|
+
network_impact["connectivity_impact"] = "HIGH"
|
667
|
+
|
718
668
|
# Check for VPC peering connections
|
719
669
|
peering_response = self.ec2_client.describe_vpc_peering_connections(
|
720
|
-
Filters=[
|
721
|
-
{'Name': 'accepter-vpc-info.vpc-id', 'Values': [vpc_id]}
|
722
|
-
]
|
670
|
+
Filters=[{"Name": "accepter-vpc-info.vpc-id", "Values": [vpc_id]}]
|
723
671
|
)
|
724
672
|
peering_response2 = self.ec2_client.describe_vpc_peering_connections(
|
725
|
-
Filters=[
|
726
|
-
{'Name': 'requester-vpc-info.vpc-id', 'Values': [vpc_id]}
|
727
|
-
]
|
673
|
+
Filters=[{"Name": "requester-vpc-info.vpc-id", "Values": [vpc_id]}]
|
728
674
|
)
|
729
|
-
|
730
|
-
total_peering = len(peering_response[
|
731
|
-
|
732
|
-
|
675
|
+
|
676
|
+
total_peering = len(peering_response["VpcPeeringConnections"]) + len(
|
677
|
+
peering_response2["VpcPeeringConnections"]
|
678
|
+
)
|
679
|
+
network_impact["peering_connections_affected"] = total_peering
|
680
|
+
|
733
681
|
if total_peering > 0:
|
734
|
-
if network_impact[
|
735
|
-
network_impact[
|
736
|
-
|
682
|
+
if network_impact["connectivity_impact"] == "NONE":
|
683
|
+
network_impact["connectivity_impact"] = "MEDIUM"
|
684
|
+
|
737
685
|
except ClientError as e:
|
738
686
|
print_warning(f"Network impact assessment failed: {e}")
|
739
|
-
|
687
|
+
|
740
688
|
result.network_impact_assessment = network_impact
|
741
|
-
|
742
|
-
def _analyze_business_risk(
|
743
|
-
self,
|
744
|
-
vpc_id: str,
|
745
|
-
vpc_info: Dict[str, Any],
|
746
|
-
result: AWSO5ArchitectureValidationResult
|
747
|
-
):
|
689
|
+
|
690
|
+
def _analyze_business_risk(self, vpc_id: str, vpc_info: Dict[str, Any], result: AWSO5ArchitectureValidationResult):
|
748
691
|
"""Comprehensive business risk analysis."""
|
749
|
-
|
692
|
+
|
750
693
|
risk_factors = []
|
751
694
|
risk_level = "LOW"
|
752
|
-
|
695
|
+
|
753
696
|
# Default VPC risk assessment
|
754
|
-
if vpc_info.get(
|
697
|
+
if vpc_info.get("IsDefault", False):
|
755
698
|
risk_factors.append("Default VPC increases security risk")
|
756
699
|
risk_factors.append("Non-compliance with CIS Benchmark")
|
757
700
|
risk_factors.append("Potential audit findings")
|
758
701
|
risk_level = "MEDIUM"
|
759
|
-
|
702
|
+
|
760
703
|
# Network connectivity risk
|
761
|
-
if result.network_impact_assessment.get(
|
762
|
-
risk_factors.append("High network connectivity impact")
|
704
|
+
if result.network_impact_assessment.get("connectivity_impact") == "HIGH":
|
705
|
+
risk_factors.append("High network connectivity impact")
|
763
706
|
risk_level = "HIGH"
|
764
|
-
elif result.network_impact_assessment.get(
|
707
|
+
elif result.network_impact_assessment.get("connectivity_impact") == "MEDIUM":
|
765
708
|
risk_factors.append("Medium network connectivity impact")
|
766
709
|
if risk_level == "LOW":
|
767
710
|
risk_level = "MEDIUM"
|
768
|
-
|
711
|
+
|
769
712
|
# Compliance risk
|
770
|
-
critical_failures = len(
|
771
|
-
cr for cr in result.compliance_results
|
772
|
-
|
773
|
-
|
774
|
-
|
713
|
+
critical_failures = len(
|
714
|
+
[cr for cr in result.compliance_results if cr.compliance_status == "FAIL" and cr.impact_level == "CRITICAL"]
|
715
|
+
)
|
716
|
+
|
775
717
|
if critical_failures > 0:
|
776
718
|
risk_factors.append(f"{critical_failures} critical compliance failures")
|
777
719
|
risk_level = "HIGH"
|
778
|
-
|
720
|
+
|
779
721
|
result.business_risk_level = risk_level
|
780
|
-
|
722
|
+
|
781
723
|
def _calculate_security_posture_score(self, result: AWSO5ArchitectureValidationResult) -> float:
|
782
724
|
"""Calculate comprehensive security posture score."""
|
783
|
-
|
725
|
+
|
784
726
|
# Base score from compliance results
|
785
727
|
compliance_score = result.overall_compliance_score
|
786
|
-
|
728
|
+
|
787
729
|
# Well-Architected security score
|
788
730
|
security_pillar_score = result.well_architected_score.get("Security", 0)
|
789
|
-
|
731
|
+
|
790
732
|
# Weighted combination
|
791
733
|
weighted_score = (compliance_score * 0.6) + (security_pillar_score * 0.4)
|
792
|
-
|
734
|
+
|
793
735
|
return weighted_score
|
794
|
-
|
736
|
+
|
795
737
|
def _generate_architecture_recommendation(self, result: AWSO5ArchitectureValidationResult):
|
796
738
|
"""Generate architecture-based cleanup recommendation."""
|
797
|
-
|
739
|
+
|
798
740
|
# Decision logic based on multiple factors
|
799
741
|
if result.business_risk_level == "LOW" and result.overall_compliance_score >= 80:
|
800
742
|
result.architecture_recommendation = "DELETE"
|
@@ -807,53 +749,59 @@ class AWSO5ArchitectureValidator:
|
|
807
749
|
result.architecture_recommendation = "INVESTIGATE"
|
808
750
|
else:
|
809
751
|
result.architecture_recommendation = "HOLD"
|
810
|
-
|
752
|
+
|
811
753
|
def _display_validation_results(self, result: AWSO5ArchitectureValidationResult):
|
812
754
|
"""Display comprehensive architecture validation results."""
|
813
|
-
|
755
|
+
|
814
756
|
# Summary table
|
815
757
|
summary_table = create_table(title="AWSO-5 Architecture Validation Summary")
|
816
758
|
summary_table.add_column("Metric", style="cyan", no_wrap=True)
|
817
759
|
summary_table.add_column("Score/Status", style="green")
|
818
760
|
summary_table.add_column("Impact", style="yellow")
|
819
|
-
|
761
|
+
|
820
762
|
summary_table.add_row("Overall Compliance Score", f"{result.overall_compliance_score:.1f}%", "")
|
821
763
|
summary_table.add_row("Security Posture Score", f"{result.security_posture_score:.1f}%", "")
|
822
|
-
summary_table.add_row(
|
823
|
-
|
764
|
+
summary_table.add_row(
|
765
|
+
"Business Risk Level",
|
766
|
+
result.business_risk_level,
|
767
|
+
"Requires Review" if result.business_risk_level in ["HIGH", "CRITICAL"] else "Acceptable",
|
768
|
+
)
|
824
769
|
summary_table.add_row("Architecture Recommendation", result.architecture_recommendation, "")
|
825
|
-
summary_table.add_row(
|
826
|
-
|
827
|
-
|
770
|
+
summary_table.add_row(
|
771
|
+
"Critical Findings",
|
772
|
+
str(len(result.critical_findings)),
|
773
|
+
"Action Required" if result.critical_findings else "None",
|
774
|
+
)
|
775
|
+
|
828
776
|
self.console.print("\n")
|
829
777
|
self.console.print(summary_table)
|
830
|
-
|
778
|
+
|
831
779
|
# Well-Architected Scores
|
832
780
|
if result.well_architected_score:
|
833
781
|
wa_table = create_table(title="AWS Well-Architected Framework Assessment")
|
834
782
|
wa_table.add_column("Pillar", style="cyan")
|
835
783
|
wa_table.add_column("Score", style="green")
|
836
784
|
wa_table.add_column("Status", style="yellow")
|
837
|
-
|
785
|
+
|
838
786
|
for pillar, score in result.well_architected_score.items():
|
839
787
|
status = "GOOD" if score >= 80 else "FAIR" if score >= 60 else "NEEDS IMPROVEMENT"
|
840
788
|
wa_table.add_row(pillar, f"{score:.1f}%", status)
|
841
|
-
|
789
|
+
|
842
790
|
self.console.print("\n")
|
843
791
|
self.console.print(wa_table)
|
844
|
-
|
792
|
+
|
845
793
|
# Critical Findings
|
846
794
|
if result.critical_findings:
|
847
795
|
self.console.print("\n[red]šØ Critical Findings:[/red]")
|
848
796
|
for finding in result.critical_findings:
|
849
797
|
self.console.print(f" ⢠{finding}")
|
850
|
-
|
798
|
+
|
851
799
|
# Security Improvements
|
852
800
|
if result.security_improvements:
|
853
801
|
self.console.print("\n[green]š Security Improvements:[/green]")
|
854
802
|
for improvement in result.security_improvements:
|
855
803
|
self.console.print(f" ⢠{improvement}")
|
856
|
-
|
804
|
+
|
857
805
|
# Architecture Recommendation
|
858
806
|
if result.architecture_recommendation == "DELETE":
|
859
807
|
status = "[green]ā
APPROVED FOR DELETION[/green]"
|
@@ -863,7 +811,7 @@ class AWSO5ArchitectureValidator:
|
|
863
811
|
status = "[red]š REQUIRES INVESTIGATION[/red]"
|
864
812
|
else:
|
865
813
|
status = "[red]ā HOLD - DO NOT DELETE[/red]"
|
866
|
-
|
814
|
+
|
867
815
|
recommendation_text = f"""
|
868
816
|
{status}
|
869
817
|
|
@@ -875,65 +823,62 @@ class AWSO5ArchitectureValidator:
|
|
875
823
|
**Next Steps:**
|
876
824
|
{self._get_architecture_next_steps(result)}
|
877
825
|
"""
|
878
|
-
|
826
|
+
|
879
827
|
from rich.panel import Panel
|
828
|
+
|
880
829
|
recommendation_panel = Panel(
|
881
|
-
recommendation_text,
|
882
|
-
title="šļø Architecture Validation Recommendation",
|
883
|
-
border_style="blue"
|
830
|
+
recommendation_text, title="šļø Architecture Validation Recommendation", border_style="blue"
|
884
831
|
)
|
885
|
-
|
832
|
+
|
886
833
|
self.console.print("\n")
|
887
834
|
self.console.print(recommendation_panel)
|
888
|
-
|
835
|
+
|
889
836
|
def _get_architecture_next_steps(self, result: AWSO5ArchitectureValidationResult) -> str:
|
890
837
|
"""Generate architecture-specific next steps."""
|
891
|
-
|
838
|
+
|
892
839
|
if result.architecture_recommendation == "DELETE":
|
893
840
|
return "⢠Architecture validation PASSED\n⢠Proceed with VPC cleanup\n⢠Update compliance documentation"
|
894
|
-
|
841
|
+
|
895
842
|
elif result.architecture_recommendation == "DELETE_WITH_REMEDIATION":
|
896
843
|
return "⢠Address critical findings first\n⢠Implement security improvements\n⢠Re-validate architecture compliance"
|
897
|
-
|
844
|
+
|
898
845
|
elif result.architecture_recommendation == "INVESTIGATE":
|
899
846
|
return "⢠Detailed risk assessment required\n⢠Stakeholder consultation needed\n⢠Consider alternative remediation approaches"
|
900
|
-
|
847
|
+
|
901
848
|
else: # HOLD
|
902
849
|
return "⢠High-risk operation detected\n⢠Comprehensive architecture review required\n⢠Platform Lead consultation mandatory"
|
903
850
|
|
904
851
|
|
905
852
|
def validate_vpc_architecture_cli(
|
906
|
-
vpc_id: str,
|
907
|
-
profile: Optional[str] = None,
|
908
|
-
region: str = "us-east-1"
|
853
|
+
vpc_id: str, profile: Optional[str] = None, region: str = "us-east-1"
|
909
854
|
) -> AWSO5ArchitectureValidationResult:
|
910
855
|
"""
|
911
856
|
CLI wrapper for VPC architecture validation.
|
912
|
-
|
857
|
+
|
913
858
|
Args:
|
914
859
|
vpc_id: AWS VPC identifier
|
915
860
|
profile: AWS profile name
|
916
861
|
region: AWS region
|
917
|
-
|
862
|
+
|
918
863
|
Returns:
|
919
864
|
Comprehensive architecture validation results
|
920
865
|
"""
|
921
866
|
session = boto3.Session(profile_name=profile) if profile else boto3.Session()
|
922
867
|
validator = AWSO5ArchitectureValidator(session=session, region=region)
|
923
|
-
|
868
|
+
|
924
869
|
return validator.validate_vpc_architecture(vpc_id)
|
925
870
|
|
926
871
|
|
927
872
|
if __name__ == "__main__":
|
928
873
|
import argparse
|
929
|
-
|
874
|
+
|
930
875
|
parser = argparse.ArgumentParser(description="AWSO-5 Architecture Validation")
|
931
876
|
parser.add_argument("--vpc-id", required=True, help="VPC ID to validate")
|
932
877
|
parser.add_argument("--profile", help="AWS profile name")
|
933
878
|
parser.add_argument("--region", default="us-east-1", help="AWS region")
|
934
|
-
|
879
|
+
|
935
880
|
args = parser.parse_args()
|
936
|
-
|
881
|
+
|
937
882
|
result = validate_vpc_architecture_cli(args.vpc_id, args.profile, args.region)
|
938
|
-
|
939
|
-
print_success(f"Architecture validation completed with {result.overall_compliance_score:.1f}% compliance score")
|
883
|
+
|
884
|
+
print_success(f"Architecture validation completed with {result.overall_compliance_score:.1f}% compliance score")
|