runbooks 1.1.4__py3-none-any.whl → 1.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (273) hide show
  1. runbooks/__init__.py +31 -2
  2. runbooks/__init___optimized.py +18 -4
  3. runbooks/_platform/__init__.py +1 -5
  4. runbooks/_platform/core/runbooks_wrapper.py +141 -138
  5. runbooks/aws2/accuracy_validator.py +812 -0
  6. runbooks/base.py +7 -0
  7. runbooks/cfat/assessment/compliance.py +1 -1
  8. runbooks/cfat/assessment/runner.py +1 -0
  9. runbooks/cfat/cloud_foundations_assessment.py +227 -239
  10. runbooks/cli/__init__.py +1 -1
  11. runbooks/cli/commands/cfat.py +64 -23
  12. runbooks/cli/commands/finops.py +1005 -54
  13. runbooks/cli/commands/inventory.py +135 -91
  14. runbooks/cli/commands/operate.py +9 -36
  15. runbooks/cli/commands/security.py +42 -18
  16. runbooks/cli/commands/validation.py +432 -18
  17. runbooks/cli/commands/vpc.py +81 -17
  18. runbooks/cli/registry.py +22 -10
  19. runbooks/cloudops/__init__.py +20 -27
  20. runbooks/cloudops/base.py +96 -107
  21. runbooks/cloudops/cost_optimizer.py +544 -542
  22. runbooks/cloudops/infrastructure_optimizer.py +5 -4
  23. runbooks/cloudops/interfaces.py +224 -225
  24. runbooks/cloudops/lifecycle_manager.py +5 -4
  25. runbooks/cloudops/mcp_cost_validation.py +252 -235
  26. runbooks/cloudops/models.py +78 -53
  27. runbooks/cloudops/monitoring_automation.py +5 -4
  28. runbooks/cloudops/notebook_framework.py +177 -213
  29. runbooks/cloudops/security_enforcer.py +125 -159
  30. runbooks/common/accuracy_validator.py +17 -12
  31. runbooks/common/aws_pricing.py +349 -326
  32. runbooks/common/aws_pricing_api.py +211 -212
  33. runbooks/common/aws_profile_manager.py +40 -36
  34. runbooks/common/aws_utils.py +74 -79
  35. runbooks/common/business_logic.py +126 -104
  36. runbooks/common/cli_decorators.py +36 -60
  37. runbooks/common/comprehensive_cost_explorer_integration.py +455 -463
  38. runbooks/common/cross_account_manager.py +197 -204
  39. runbooks/common/date_utils.py +27 -39
  40. runbooks/common/decorators.py +29 -19
  41. runbooks/common/dry_run_examples.py +173 -208
  42. runbooks/common/dry_run_framework.py +157 -155
  43. runbooks/common/enhanced_exception_handler.py +15 -4
  44. runbooks/common/enhanced_logging_example.py +50 -64
  45. runbooks/common/enhanced_logging_integration_example.py +65 -37
  46. runbooks/common/env_utils.py +16 -16
  47. runbooks/common/error_handling.py +40 -38
  48. runbooks/common/lazy_loader.py +41 -23
  49. runbooks/common/logging_integration_helper.py +79 -86
  50. runbooks/common/mcp_cost_explorer_integration.py +476 -493
  51. runbooks/common/mcp_integration.py +99 -79
  52. runbooks/common/memory_optimization.py +140 -118
  53. runbooks/common/module_cli_base.py +37 -58
  54. runbooks/common/organizations_client.py +175 -193
  55. runbooks/common/patterns.py +23 -25
  56. runbooks/common/performance_monitoring.py +67 -71
  57. runbooks/common/performance_optimization_engine.py +283 -274
  58. runbooks/common/profile_utils.py +111 -37
  59. runbooks/common/rich_utils.py +315 -141
  60. runbooks/common/sre_performance_suite.py +177 -186
  61. runbooks/enterprise/__init__.py +1 -1
  62. runbooks/enterprise/logging.py +144 -106
  63. runbooks/enterprise/security.py +187 -204
  64. runbooks/enterprise/validation.py +43 -56
  65. runbooks/finops/__init__.py +26 -30
  66. runbooks/finops/account_resolver.py +1 -1
  67. runbooks/finops/advanced_optimization_engine.py +980 -0
  68. runbooks/finops/automation_core.py +268 -231
  69. runbooks/finops/business_case_config.py +184 -179
  70. runbooks/finops/cli.py +660 -139
  71. runbooks/finops/commvault_ec2_analysis.py +157 -164
  72. runbooks/finops/compute_cost_optimizer.py +336 -320
  73. runbooks/finops/config.py +20 -20
  74. runbooks/finops/cost_optimizer.py +484 -618
  75. runbooks/finops/cost_processor.py +332 -214
  76. runbooks/finops/dashboard_runner.py +1006 -172
  77. runbooks/finops/ebs_cost_optimizer.py +991 -657
  78. runbooks/finops/elastic_ip_optimizer.py +317 -257
  79. runbooks/finops/enhanced_mcp_integration.py +340 -0
  80. runbooks/finops/enhanced_progress.py +32 -29
  81. runbooks/finops/enhanced_trend_visualization.py +3 -2
  82. runbooks/finops/enterprise_wrappers.py +223 -285
  83. runbooks/finops/executive_export.py +203 -160
  84. runbooks/finops/helpers.py +130 -288
  85. runbooks/finops/iam_guidance.py +1 -1
  86. runbooks/finops/infrastructure/__init__.py +80 -0
  87. runbooks/finops/infrastructure/commands.py +506 -0
  88. runbooks/finops/infrastructure/load_balancer_optimizer.py +866 -0
  89. runbooks/finops/infrastructure/vpc_endpoint_optimizer.py +832 -0
  90. runbooks/finops/markdown_exporter.py +337 -174
  91. runbooks/finops/mcp_validator.py +1952 -0
  92. runbooks/finops/nat_gateway_optimizer.py +1512 -481
  93. runbooks/finops/network_cost_optimizer.py +657 -587
  94. runbooks/finops/notebook_utils.py +226 -188
  95. runbooks/finops/optimization_engine.py +1136 -0
  96. runbooks/finops/optimizer.py +19 -23
  97. runbooks/finops/rds_snapshot_optimizer.py +367 -411
  98. runbooks/finops/reservation_optimizer.py +427 -363
  99. runbooks/finops/scenario_cli_integration.py +64 -65
  100. runbooks/finops/scenarios.py +1277 -438
  101. runbooks/finops/schemas.py +218 -182
  102. runbooks/finops/snapshot_manager.py +2289 -0
  103. runbooks/finops/types.py +3 -3
  104. runbooks/finops/validation_framework.py +259 -265
  105. runbooks/finops/vpc_cleanup_exporter.py +189 -144
  106. runbooks/finops/vpc_cleanup_optimizer.py +591 -573
  107. runbooks/finops/workspaces_analyzer.py +171 -182
  108. runbooks/integration/__init__.py +89 -0
  109. runbooks/integration/mcp_integration.py +1920 -0
  110. runbooks/inventory/CLAUDE.md +816 -0
  111. runbooks/inventory/__init__.py +2 -2
  112. runbooks/inventory/aws_decorators.py +2 -3
  113. runbooks/inventory/check_cloudtrail_compliance.py +2 -4
  114. runbooks/inventory/check_controltower_readiness.py +152 -151
  115. runbooks/inventory/check_landingzone_readiness.py +85 -84
  116. runbooks/inventory/cloud_foundations_integration.py +144 -149
  117. runbooks/inventory/collectors/aws_comprehensive.py +1 -1
  118. runbooks/inventory/collectors/aws_networking.py +109 -99
  119. runbooks/inventory/collectors/base.py +4 -0
  120. runbooks/inventory/core/collector.py +495 -313
  121. runbooks/inventory/core/formatter.py +11 -0
  122. runbooks/inventory/draw_org_structure.py +8 -9
  123. runbooks/inventory/drift_detection_cli.py +69 -96
  124. runbooks/inventory/ec2_vpc_utils.py +2 -2
  125. runbooks/inventory/find_cfn_drift_detection.py +5 -7
  126. runbooks/inventory/find_cfn_orphaned_stacks.py +7 -9
  127. runbooks/inventory/find_cfn_stackset_drift.py +5 -6
  128. runbooks/inventory/find_ec2_security_groups.py +48 -42
  129. runbooks/inventory/find_landingzone_versions.py +4 -6
  130. runbooks/inventory/find_vpc_flow_logs.py +7 -9
  131. runbooks/inventory/inventory_mcp_cli.py +48 -46
  132. runbooks/inventory/inventory_modules.py +103 -91
  133. runbooks/inventory/list_cfn_stacks.py +9 -10
  134. runbooks/inventory/list_cfn_stackset_operation_results.py +1 -3
  135. runbooks/inventory/list_cfn_stackset_operations.py +79 -57
  136. runbooks/inventory/list_cfn_stacksets.py +8 -10
  137. runbooks/inventory/list_config_recorders_delivery_channels.py +49 -39
  138. runbooks/inventory/list_ds_directories.py +65 -53
  139. runbooks/inventory/list_ec2_availability_zones.py +2 -4
  140. runbooks/inventory/list_ec2_ebs_volumes.py +32 -35
  141. runbooks/inventory/list_ec2_instances.py +23 -28
  142. runbooks/inventory/list_ecs_clusters_and_tasks.py +26 -34
  143. runbooks/inventory/list_elbs_load_balancers.py +22 -20
  144. runbooks/inventory/list_enis_network_interfaces.py +26 -33
  145. runbooks/inventory/list_guardduty_detectors.py +2 -4
  146. runbooks/inventory/list_iam_policies.py +2 -4
  147. runbooks/inventory/list_iam_roles.py +5 -7
  148. runbooks/inventory/list_iam_saml_providers.py +4 -6
  149. runbooks/inventory/list_lambda_functions.py +38 -38
  150. runbooks/inventory/list_org_accounts.py +6 -8
  151. runbooks/inventory/list_org_accounts_users.py +55 -44
  152. runbooks/inventory/list_rds_db_instances.py +31 -33
  153. runbooks/inventory/list_rds_snapshots_aggregator.py +192 -208
  154. runbooks/inventory/list_route53_hosted_zones.py +3 -5
  155. runbooks/inventory/list_servicecatalog_provisioned_products.py +37 -41
  156. runbooks/inventory/list_sns_topics.py +2 -4
  157. runbooks/inventory/list_ssm_parameters.py +4 -7
  158. runbooks/inventory/list_vpc_subnets.py +2 -4
  159. runbooks/inventory/list_vpcs.py +7 -10
  160. runbooks/inventory/mcp_inventory_validator.py +554 -468
  161. runbooks/inventory/mcp_vpc_validator.py +359 -442
  162. runbooks/inventory/organizations_discovery.py +63 -55
  163. runbooks/inventory/recover_cfn_stack_ids.py +7 -8
  164. runbooks/inventory/requirements.txt +0 -1
  165. runbooks/inventory/rich_inventory_display.py +35 -34
  166. runbooks/inventory/run_on_multi_accounts.py +3 -5
  167. runbooks/inventory/unified_validation_engine.py +281 -253
  168. runbooks/inventory/verify_ec2_security_groups.py +1 -1
  169. runbooks/inventory/vpc_analyzer.py +735 -697
  170. runbooks/inventory/vpc_architecture_validator.py +293 -348
  171. runbooks/inventory/vpc_dependency_analyzer.py +384 -380
  172. runbooks/inventory/vpc_flow_analyzer.py +1 -1
  173. runbooks/main.py +49 -34
  174. runbooks/main_final.py +91 -60
  175. runbooks/main_minimal.py +22 -10
  176. runbooks/main_optimized.py +131 -100
  177. runbooks/main_ultra_minimal.py +7 -2
  178. runbooks/mcp/__init__.py +36 -0
  179. runbooks/mcp/integration.py +679 -0
  180. runbooks/monitoring/performance_monitor.py +9 -4
  181. runbooks/operate/dynamodb_operations.py +3 -1
  182. runbooks/operate/ec2_operations.py +145 -137
  183. runbooks/operate/iam_operations.py +146 -152
  184. runbooks/operate/networking_cost_heatmap.py +29 -8
  185. runbooks/operate/rds_operations.py +223 -254
  186. runbooks/operate/s3_operations.py +107 -118
  187. runbooks/operate/vpc_operations.py +646 -616
  188. runbooks/remediation/base.py +1 -1
  189. runbooks/remediation/commons.py +10 -7
  190. runbooks/remediation/commvault_ec2_analysis.py +70 -66
  191. runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
  192. runbooks/remediation/multi_account.py +24 -21
  193. runbooks/remediation/rds_snapshot_list.py +86 -60
  194. runbooks/remediation/remediation_cli.py +92 -146
  195. runbooks/remediation/universal_account_discovery.py +83 -79
  196. runbooks/remediation/workspaces_list.py +46 -41
  197. runbooks/security/__init__.py +19 -0
  198. runbooks/security/assessment_runner.py +1150 -0
  199. runbooks/security/baseline_checker.py +812 -0
  200. runbooks/security/cloudops_automation_security_validator.py +509 -535
  201. runbooks/security/compliance_automation_engine.py +17 -17
  202. runbooks/security/config/__init__.py +2 -2
  203. runbooks/security/config/compliance_config.py +50 -50
  204. runbooks/security/config_template_generator.py +63 -76
  205. runbooks/security/enterprise_security_framework.py +1 -1
  206. runbooks/security/executive_security_dashboard.py +519 -508
  207. runbooks/security/multi_account_security_controls.py +959 -1210
  208. runbooks/security/real_time_security_monitor.py +422 -444
  209. runbooks/security/security_baseline_tester.py +1 -1
  210. runbooks/security/security_cli.py +143 -112
  211. runbooks/security/test_2way_validation.py +439 -0
  212. runbooks/security/two_way_validation_framework.py +852 -0
  213. runbooks/sre/production_monitoring_framework.py +167 -177
  214. runbooks/tdd/__init__.py +15 -0
  215. runbooks/tdd/cli.py +1071 -0
  216. runbooks/utils/__init__.py +14 -17
  217. runbooks/utils/logger.py +7 -2
  218. runbooks/utils/version_validator.py +50 -47
  219. runbooks/validation/__init__.py +6 -6
  220. runbooks/validation/cli.py +9 -3
  221. runbooks/validation/comprehensive_2way_validator.py +745 -704
  222. runbooks/validation/mcp_validator.py +906 -228
  223. runbooks/validation/terraform_citations_validator.py +104 -115
  224. runbooks/validation/terraform_drift_detector.py +461 -454
  225. runbooks/vpc/README.md +617 -0
  226. runbooks/vpc/__init__.py +8 -1
  227. runbooks/vpc/analyzer.py +577 -0
  228. runbooks/vpc/cleanup_wrapper.py +476 -413
  229. runbooks/vpc/cli_cloudtrail_commands.py +339 -0
  230. runbooks/vpc/cli_mcp_validation_commands.py +480 -0
  231. runbooks/vpc/cloudtrail_audit_integration.py +717 -0
  232. runbooks/vpc/config.py +92 -97
  233. runbooks/vpc/cost_engine.py +411 -148
  234. runbooks/vpc/cost_explorer_integration.py +553 -0
  235. runbooks/vpc/cross_account_session.py +101 -106
  236. runbooks/vpc/enhanced_mcp_validation.py +917 -0
  237. runbooks/vpc/eni_gate_validator.py +961 -0
  238. runbooks/vpc/heatmap_engine.py +185 -160
  239. runbooks/vpc/mcp_no_eni_validator.py +680 -639
  240. runbooks/vpc/nat_gateway_optimizer.py +358 -0
  241. runbooks/vpc/networking_wrapper.py +15 -8
  242. runbooks/vpc/pdca_remediation_planner.py +528 -0
  243. runbooks/vpc/performance_optimized_analyzer.py +219 -231
  244. runbooks/vpc/runbooks_adapter.py +1167 -241
  245. runbooks/vpc/tdd_red_phase_stubs.py +601 -0
  246. runbooks/vpc/test_data_loader.py +358 -0
  247. runbooks/vpc/tests/conftest.py +314 -4
  248. runbooks/vpc/tests/test_cleanup_framework.py +1022 -0
  249. runbooks/vpc/tests/test_cost_engine.py +0 -2
  250. runbooks/vpc/topology_generator.py +326 -0
  251. runbooks/vpc/unified_scenarios.py +1297 -1124
  252. runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
  253. runbooks-1.1.6.dist-info/METADATA +327 -0
  254. runbooks-1.1.6.dist-info/RECORD +489 -0
  255. runbooks/finops/README.md +0 -414
  256. runbooks/finops/accuracy_cross_validator.py +0 -647
  257. runbooks/finops/business_cases.py +0 -950
  258. runbooks/finops/dashboard_router.py +0 -922
  259. runbooks/finops/ebs_optimizer.py +0 -973
  260. runbooks/finops/embedded_mcp_validator.py +0 -1629
  261. runbooks/finops/enhanced_dashboard_runner.py +0 -527
  262. runbooks/finops/finops_dashboard.py +0 -584
  263. runbooks/finops/finops_scenarios.py +0 -1218
  264. runbooks/finops/legacy_migration.py +0 -730
  265. runbooks/finops/multi_dashboard.py +0 -1519
  266. runbooks/finops/single_dashboard.py +0 -1113
  267. runbooks/finops/unlimited_scenarios.py +0 -393
  268. runbooks-1.1.4.dist-info/METADATA +0 -800
  269. runbooks-1.1.4.dist-info/RECORD +0 -468
  270. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/WHEEL +0 -0
  271. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/entry_points.txt +0 -0
  272. {runbooks-1.1.4.dist-info → runbooks-1.1.6.dist-info}/licenses/LICENSE +0 -0
  273. {runbooks-1.1.4.dist-info → runbooks-1.1.6.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, print_header, print_success, print_error, print_warning,
41
- create_table, create_progress_bar, STATUS_INDICATORS
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
- 'CIS': 3.0,
115
- 'Well-Architected': 2.5,
116
- 'SOC2': 2.0,
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('ec2', region_name=self.region)
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('organizations', region_name='us-east-1')
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('config', region_name=self.region)
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('cloudtrail', region_name=self.region)
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('sts').get_caller_identity()['Account']
213
-
214
- result = AWSO5ArchitectureValidationResult(
215
- vpc_id=vpc_id,
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['Vpcs'][0] if response['Vpcs'] else None
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('IsDefault', False):
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
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
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['SecurityGroups']:
299
- for rule in sg.get('IpPermissions', []):
300
- if (rule.get('FromPort') == 22 and rule.get('ToPort') == 22 and
301
- any(ip_range.get('CidrIp') == '0.0.0.0/0' for ip_range in rule.get('IpRanges', []))):
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
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
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['SecurityGroups']:
339
- for rule in sg.get('IpPermissions', []):
340
- if (rule.get('FromPort') == 3389 and rule.get('ToPort') == 3389 and
341
- any(ip_range.get('CidrIp') == '0.0.0.0/0' for ip_range in rule.get('IpRanges', []))):
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['SecurityGroups']:
382
- if sg.get('IpPermissions') or sg.get('IpPermissionsEgress'):
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
- fl for fl in response['FlowLogs']
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
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
518
- )['NetworkAcls']
519
-
520
- sgs = self.ec2_client.describe_security_groups(
521
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
522
- )['SecurityGroups']
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('IsDefault', False):
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
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
573
- )['Subnets']
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
- Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
606
- )['VpcEndpoints']
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('IsDefault', False):
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('IsDefault', False):
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
- "Default VPC elimination reduces attack surface by ~30%",
685
- "Custom VPC implementation enables security best practices",
686
- "Network segmentation improves compliance posture"
687
- ])
688
-
689
- def _assess_network_impact(
690
- self,
691
- vpc_id: str,
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
- 'connectivity_impact': 'NONE', # NONE, LOW, MEDIUM, HIGH
699
- 'routing_changes_required': False,
700
- 'cross_account_dependencies': [],
701
- 'transit_gateway_impact': False,
702
- 'peering_connections_affected': 0
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
- {'Name': 'resource-id', 'Values': [vpc_id]},
710
- {'Name': 'resource-type', 'Values': ['vpc']}
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['transit_gateway_impact'] = True
716
- network_impact['connectivity_impact'] = 'HIGH'
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['VpcPeeringConnections']) + len(peering_response2['VpcPeeringConnections'])
731
- network_impact['peering_connections_affected'] = total_peering
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['connectivity_impact'] == 'NONE':
735
- network_impact['connectivity_impact'] = 'MEDIUM'
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('IsDefault', False):
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('connectivity_impact') == 'HIGH':
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('connectivity_impact') == 'MEDIUM':
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
- if cr.compliance_status == "FAIL" and cr.impact_level == "CRITICAL"
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("Business Risk Level", result.business_risk_level,
823
- "Requires Review" if result.business_risk_level in ["HIGH", "CRITICAL"] else "Acceptable")
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("Critical Findings", str(len(result.critical_findings)),
826
- "Action Required" if result.critical_findings else "None")
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")