runbooks 1.1.3__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/WEIGHT_CONFIG_README.md +1 -1
- runbooks/cfat/assessment/compliance.py +8 -8
- runbooks/cfat/assessment/runner.py +1 -0
- runbooks/cfat/cloud_foundations_assessment.py +227 -239
- runbooks/cfat/models.py +6 -2
- runbooks/cfat/tests/__init__.py +6 -1
- runbooks/cli/__init__.py +13 -0
- runbooks/cli/commands/cfat.py +274 -0
- runbooks/cli/commands/finops.py +1164 -0
- runbooks/cli/commands/inventory.py +379 -0
- runbooks/cli/commands/operate.py +239 -0
- runbooks/cli/commands/security.py +248 -0
- runbooks/cli/commands/validation.py +825 -0
- runbooks/cli/commands/vpc.py +310 -0
- runbooks/cli/registry.py +107 -0
- runbooks/cloudops/__init__.py +23 -30
- runbooks/cloudops/base.py +96 -107
- runbooks/cloudops/cost_optimizer.py +549 -547
- runbooks/cloudops/infrastructure_optimizer.py +5 -4
- runbooks/cloudops/interfaces.py +226 -227
- 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 +179 -215
- 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 +341 -0
- runbooks/common/aws_utils.py +75 -80
- runbooks/common/business_logic.py +127 -105
- runbooks/common/cli_decorators.py +36 -60
- runbooks/common/comprehensive_cost_explorer_integration.py +456 -464
- runbooks/common/cross_account_manager.py +198 -205
- runbooks/common/date_utils.py +27 -39
- runbooks/common/decorators.py +235 -0
- 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 +478 -495
- 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 +176 -194
- runbooks/common/patterns.py +204 -0
- runbooks/common/performance_monitoring.py +67 -71
- runbooks/common/performance_optimization_engine.py +283 -274
- runbooks/common/profile_utils.py +248 -39
- runbooks/common/rich_utils.py +643 -92
- 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 +29 -33
- 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 +488 -622
- 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 +40 -37
- runbooks/finops/enhanced_trend_visualization.py +3 -2
- runbooks/finops/enterprise_wrappers.py +230 -292
- 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 +338 -175
- runbooks/finops/mcp_validator.py +1952 -0
- runbooks/finops/nat_gateway_optimizer.py +1513 -482
- 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 +25 -29
- runbooks/finops/rds_snapshot_optimizer.py +367 -411
- runbooks/finops/reservation_optimizer.py +427 -363
- runbooks/finops/scenario_cli_integration.py +77 -78
- runbooks/finops/scenarios.py +1278 -439
- runbooks/finops/schemas.py +218 -182
- runbooks/finops/snapshot_manager.py +2289 -0
- runbooks/finops/tests/test_finops_dashboard.py +3 -3
- runbooks/finops/tests/test_reference_images_validation.py +2 -2
- runbooks/finops/tests/test_single_account_features.py +17 -17
- runbooks/finops/tests/validate_test_suite.py +1 -1
- runbooks/finops/types.py +3 -3
- runbooks/finops/validation_framework.py +263 -269
- runbooks/finops/vpc_cleanup_exporter.py +191 -146
- runbooks/finops/vpc_cleanup_optimizer.py +593 -575
- runbooks/finops/workspaces_analyzer.py +171 -182
- runbooks/hitl/enhanced_workflow_engine.py +1 -1
- runbooks/integration/__init__.py +89 -0
- runbooks/integration/mcp_integration.py +1920 -0
- runbooks/inventory/CLAUDE.md +816 -0
- runbooks/inventory/README.md +3 -3
- runbooks/inventory/Tests/common_test_data.py +30 -30
- runbooks/inventory/__init__.py +2 -2
- runbooks/inventory/cloud_foundations_integration.py +144 -149
- runbooks/inventory/collectors/aws_comprehensive.py +28 -11
- runbooks/inventory/collectors/aws_networking.py +111 -101
- runbooks/inventory/collectors/base.py +4 -0
- runbooks/inventory/core/collector.py +495 -313
- runbooks/inventory/discovery.md +2 -2
- runbooks/inventory/drift_detection_cli.py +69 -96
- runbooks/inventory/find_ec2_security_groups.py +1 -1
- 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 +56 -52
- runbooks/inventory/rich_inventory_display.py +33 -32
- runbooks/inventory/unified_validation_engine.py +278 -251
- runbooks/inventory/vpc_analyzer.py +733 -696
- runbooks/inventory/vpc_architecture_validator.py +293 -348
- runbooks/inventory/vpc_dependency_analyzer.py +382 -378
- runbooks/inventory/vpc_flow_analyzer.py +3 -3
- runbooks/main.py +152 -9147
- 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/metrics/dora_metrics_engine.py +2 -2
- 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/mcp_integration.py +1 -1
- runbooks/operate/networking_cost_heatmap.py +33 -10
- runbooks/operate/privatelink_operations.py +1 -1
- runbooks/operate/rds_operations.py +223 -254
- runbooks/operate/s3_operations.py +107 -118
- runbooks/operate/vpc_endpoints.py +1 -1
- runbooks/operate/vpc_operations.py +648 -618
- runbooks/remediation/base.py +1 -1
- runbooks/remediation/commons.py +10 -7
- runbooks/remediation/commvault_ec2_analysis.py +71 -67
- runbooks/remediation/ec2_unattached_ebs_volumes.py +1 -0
- runbooks/remediation/multi_account.py +24 -21
- runbooks/remediation/rds_snapshot_list.py +91 -65
- runbooks/remediation/remediation_cli.py +92 -146
- runbooks/remediation/universal_account_discovery.py +83 -79
- runbooks/remediation/workspaces_list.py +49 -44
- 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/integration_test_enterprise_security.py +5 -3
- runbooks/security/multi_account_security_controls.py +959 -1210
- runbooks/security/real_time_security_monitor.py +422 -444
- runbooks/security/run_script.py +1 -1
- 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/mcp_reliability_engine.py +6 -6
- 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 +51 -48
- runbooks/validation/__init__.py +6 -6
- runbooks/validation/cli.py +9 -3
- runbooks/validation/comprehensive_2way_validator.py +754 -708
- 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 +190 -162
- runbooks/vpc/mcp_no_eni_validator.py +681 -640
- 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 +1302 -1129
- runbooks/vpc/vpc_cleanup_integration.py +1943 -1115
- runbooks-1.1.5.dist-info/METADATA +328 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/RECORD +233 -200
- 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 -956
- 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.3.dist-info/METADATA +0 -799
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/WHEEL +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/entry_points.txt +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/licenses/LICENSE +0 -0
- {runbooks-1.1.3.dist-info → runbooks-1.1.5.dist-info}/top_level.txt +0 -0
runbooks/enterprise/security.py
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
Enterprise Security Module - Enhanced Security Logging & VPC Security Assessment
|
3
3
|
===============================================================================
|
4
4
|
|
5
|
-
Enterprise-grade security module providing enhanced security logging, VPC security
|
5
|
+
Enterprise-grade security module providing enhanced security logging, VPC security
|
6
6
|
assessment, compliance framework integration, and risk classification for the
|
7
|
-
CloudOps Runbooks platform. This module integrates with the three-bucket VPC
|
7
|
+
CloudOps Runbooks platform. This module integrates with the three-bucket VPC
|
8
8
|
cleanup strategy and provides comprehensive security audit trails.
|
9
9
|
|
10
10
|
Key Features:
|
@@ -37,14 +37,14 @@ from botocore.exceptions import ClientError, NoCredentialsError
|
|
37
37
|
from runbooks.common.rich_utils import (
|
38
38
|
console,
|
39
39
|
create_panel,
|
40
|
-
create_progress_bar,
|
40
|
+
create_progress_bar,
|
41
41
|
create_table,
|
42
42
|
print_error,
|
43
43
|
print_info,
|
44
44
|
print_success,
|
45
45
|
print_warning,
|
46
46
|
STATUS_INDICATORS,
|
47
|
-
CLOUDOPS_THEME
|
47
|
+
CLOUDOPS_THEME,
|
48
48
|
)
|
49
49
|
|
50
50
|
# Profile management integration
|
@@ -58,16 +58,16 @@ except ImportError:
|
|
58
58
|
|
59
59
|
class SecurityRiskLevel(Enum):
|
60
60
|
"""Security risk classification levels for enterprise decision making."""
|
61
|
-
|
61
|
+
|
62
62
|
LOW = "LOW"
|
63
|
-
MEDIUM = "MEDIUM"
|
63
|
+
MEDIUM = "MEDIUM"
|
64
64
|
HIGH = "HIGH"
|
65
65
|
CRITICAL = "CRITICAL"
|
66
66
|
|
67
67
|
|
68
68
|
class ComplianceFramework(Enum):
|
69
69
|
"""Supported compliance frameworks for enterprise validation."""
|
70
|
-
|
70
|
+
|
71
71
|
SOC2 = "SOC2"
|
72
72
|
PCI_DSS = "PCI-DSS"
|
73
73
|
HIPAA = "HIPAA"
|
@@ -79,7 +79,7 @@ class ComplianceFramework(Enum):
|
|
79
79
|
|
80
80
|
class VPCSecurityAnalysis:
|
81
81
|
"""VPC Security Analysis results for cleanup integration."""
|
82
|
-
|
82
|
+
|
83
83
|
def __init__(self, vpc_id: str, region: str):
|
84
84
|
self.vpc_id = vpc_id
|
85
85
|
self.region = region
|
@@ -91,7 +91,7 @@ class VPCSecurityAnalysis:
|
|
91
91
|
self.findings: List[Dict[str, Any]] = []
|
92
92
|
self.risk_level = SecurityRiskLevel.LOW
|
93
93
|
self.compliance_status: Dict[str, bool] = {}
|
94
|
-
|
94
|
+
|
95
95
|
def add_finding(self, severity: str, title: str, description: str, resource: str):
|
96
96
|
"""Add a security finding to the analysis."""
|
97
97
|
finding = {
|
@@ -100,10 +100,10 @@ class VPCSecurityAnalysis:
|
|
100
100
|
"description": description,
|
101
101
|
"resource": resource,
|
102
102
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
103
|
-
"vpc_id": self.vpc_id
|
103
|
+
"vpc_id": self.vpc_id,
|
104
104
|
}
|
105
105
|
self.findings.append(finding)
|
106
|
-
|
106
|
+
|
107
107
|
# Update overall risk level based on findings
|
108
108
|
if severity == "HIGH" or severity == "CRITICAL":
|
109
109
|
if self.risk_level in [SecurityRiskLevel.LOW, SecurityRiskLevel.MEDIUM]:
|
@@ -114,11 +114,11 @@ class VPCSecurityAnalysis:
|
|
114
114
|
|
115
115
|
class EnterpriseSecurityLogger:
|
116
116
|
"""Enhanced security logger with enterprise audit trails and Rich CLI integration."""
|
117
|
-
|
117
|
+
|
118
118
|
def __init__(self, module_name: str, log_dir: Optional[Path] = None):
|
119
119
|
"""
|
120
120
|
Initialize enterprise security logger.
|
121
|
-
|
121
|
+
|
122
122
|
Args:
|
123
123
|
module_name: Name of the module requesting logging
|
124
124
|
log_dir: Optional directory for security logs
|
@@ -126,33 +126,33 @@ class EnterpriseSecurityLogger:
|
|
126
126
|
self.module_name = module_name
|
127
127
|
self.log_dir = log_dir or Path.home() / ".runbooks" / "security-logs"
|
128
128
|
self.log_dir.mkdir(parents=True, exist_ok=True)
|
129
|
-
|
129
|
+
|
130
130
|
# Create security-specific log file
|
131
131
|
self.log_file = self.log_dir / f"{module_name}-security-{datetime.now().strftime('%Y%m%d')}.jsonl"
|
132
|
-
|
132
|
+
|
133
133
|
# Initialize standard logger as fallback
|
134
134
|
self.logger = logging.getLogger(f"runbooks.security.{module_name}")
|
135
135
|
self.logger.setLevel(logging.INFO)
|
136
|
-
|
136
|
+
|
137
137
|
if not self.logger.handlers:
|
138
138
|
# Console handler with Rich CLI integration
|
139
139
|
console_handler = logging.StreamHandler()
|
140
|
-
console_handler.setFormatter(
|
141
|
-
f"{STATUS_INDICATORS['info']} %(asctime)s | SECURITY | %(message)s"
|
142
|
-
)
|
140
|
+
console_handler.setFormatter(
|
141
|
+
logging.Formatter(f"{STATUS_INDICATORS['info']} %(asctime)s | SECURITY | %(message)s")
|
142
|
+
)
|
143
143
|
self.logger.addHandler(console_handler)
|
144
|
-
|
144
|
+
|
145
145
|
# File handler for audit trails
|
146
146
|
file_handler = logging.FileHandler(self.log_file)
|
147
|
-
file_handler.setFormatter(
|
148
|
-
|
149
|
-
)
|
147
|
+
file_handler.setFormatter(
|
148
|
+
logging.Formatter("%(asctime)s | %(levelname)s | SECURITY | %(name)s | %(message)s")
|
149
|
+
)
|
150
150
|
self.logger.addHandler(file_handler)
|
151
|
-
|
151
|
+
|
152
152
|
def log_security_event(self, event_type: str, message: str, metadata: Optional[Dict[str, Any]] = None):
|
153
153
|
"""
|
154
154
|
Log a security event with comprehensive audit trail.
|
155
|
-
|
155
|
+
|
156
156
|
Args:
|
157
157
|
event_type: Type of security event (VPC_ANALYSIS, COMPLIANCE_CHECK, etc.)
|
158
158
|
message: Human-readable message
|
@@ -164,23 +164,23 @@ class EnterpriseSecurityLogger:
|
|
164
164
|
"event_type": event_type,
|
165
165
|
"message": message,
|
166
166
|
"metadata": metadata or {},
|
167
|
-
"correlation_id": self._generate_correlation_id()
|
167
|
+
"correlation_id": self._generate_correlation_id(),
|
168
168
|
}
|
169
|
-
|
169
|
+
|
170
170
|
# Generate SHA256 hash for tamper detection
|
171
171
|
event_hash = self._generate_event_hash(security_event)
|
172
172
|
security_event["event_hash"] = event_hash
|
173
|
-
|
173
|
+
|
174
174
|
# Write to audit file
|
175
|
-
with open(self.log_file,
|
176
|
-
f.write(json.dumps(security_event) +
|
177
|
-
|
175
|
+
with open(self.log_file, "a") as f:
|
176
|
+
f.write(json.dumps(security_event) + "\n")
|
177
|
+
|
178
178
|
# Rich CLI output
|
179
179
|
console.print(f"{STATUS_INDICATORS['info']} [security]SECURITY[/security] | {event_type} | {message}")
|
180
|
-
|
180
|
+
|
181
181
|
# Standard logger
|
182
182
|
self.logger.info(f"{event_type} | {message} | Hash: {event_hash[:8]}...")
|
183
|
-
|
183
|
+
|
184
184
|
def log_vpc_security_analysis(self, analysis: VPCSecurityAnalysis):
|
185
185
|
"""Log VPC security analysis results."""
|
186
186
|
self.log_security_event(
|
@@ -194,21 +194,22 @@ class EnterpriseSecurityLogger:
|
|
194
194
|
"compliance_status": analysis.compliance_status,
|
195
195
|
"security_groups_count": len(analysis.security_groups),
|
196
196
|
"nacls_count": len(analysis.nacls),
|
197
|
-
"flow_logs_enabled": len(analysis.flow_logs) > 0
|
198
|
-
}
|
197
|
+
"flow_logs_enabled": len(analysis.flow_logs) > 0,
|
198
|
+
},
|
199
199
|
)
|
200
|
-
|
200
|
+
|
201
201
|
def _generate_correlation_id(self) -> str:
|
202
202
|
"""Generate unique correlation ID for tracking operations."""
|
203
203
|
import uuid
|
204
|
+
|
204
205
|
return str(uuid.uuid4())[:8]
|
205
|
-
|
206
|
+
|
206
207
|
def _generate_event_hash(self, event_data: Dict[str, Any]) -> str:
|
207
208
|
"""Generate SHA256 hash for security event integrity."""
|
208
209
|
# Remove hash field if present to avoid circular reference
|
209
210
|
event_copy = event_data.copy()
|
210
211
|
event_copy.pop("event_hash", None)
|
211
|
-
|
212
|
+
|
212
213
|
# Create deterministic string representation
|
213
214
|
event_string = json.dumps(event_copy, sort_keys=True)
|
214
215
|
return hashlib.sha256(event_string.encode()).hexdigest()
|
@@ -217,13 +218,13 @@ class EnterpriseSecurityLogger:
|
|
217
218
|
def get_enhanced_logger(module_name: str) -> EnterpriseSecurityLogger:
|
218
219
|
"""
|
219
220
|
Get enhanced security logger for enterprise audit trails.
|
220
|
-
|
221
|
+
|
221
222
|
This is the main function called by VPC cleanup and other modules
|
222
223
|
that need enhanced security logging capabilities.
|
223
|
-
|
224
|
+
|
224
225
|
Args:
|
225
226
|
module_name: Name of the requesting module
|
226
|
-
|
227
|
+
|
227
228
|
Returns:
|
228
229
|
EnterpriseSecurityLogger instance with audit trail capabilities
|
229
230
|
"""
|
@@ -233,111 +234,112 @@ def get_enhanced_logger(module_name: str) -> EnterpriseSecurityLogger:
|
|
233
234
|
def assess_vpc_security_posture(vpc_id: str, profile: str, region: str = "us-east-1") -> VPCSecurityAnalysis:
|
234
235
|
"""
|
235
236
|
Comprehensive VPC security posture assessment.
|
236
|
-
|
237
|
+
|
237
238
|
Analyzes VPC security configuration including Security Groups, NACLs,
|
238
239
|
Flow Logs, and route tables to identify security risks and compliance
|
239
240
|
issues before VPC cleanup operations.
|
240
|
-
|
241
|
+
|
241
242
|
Args:
|
242
243
|
vpc_id: VPC ID to analyze
|
243
244
|
profile: AWS profile for authentication
|
244
245
|
region: AWS region (default: us-east-1)
|
245
|
-
|
246
|
+
|
246
247
|
Returns:
|
247
248
|
VPCSecurityAnalysis object with comprehensive security findings
|
248
249
|
"""
|
249
250
|
console.print(f"{STATUS_INDICATORS['running']} [security]Assessing VPC security posture for {vpc_id}[/security]")
|
250
|
-
|
251
|
+
|
251
252
|
analysis = VPCSecurityAnalysis(vpc_id, region)
|
252
|
-
|
253
|
+
|
253
254
|
try:
|
254
255
|
# Create AWS session with specified profile
|
255
256
|
session = create_session(profile)
|
256
|
-
ec2 = session.client(
|
257
|
-
|
257
|
+
ec2 = session.client("ec2", region_name=region)
|
258
|
+
|
258
259
|
with create_progress_bar() as progress:
|
259
260
|
task = progress.add_task("[security]Security Assessment[/security]", total=4)
|
260
|
-
|
261
|
+
|
261
262
|
# 1. Analyze Security Groups
|
262
263
|
progress.update(task, description="[security]Analyzing Security Groups[/security]")
|
263
264
|
security_groups = _analyze_security_groups(ec2, vpc_id, analysis)
|
264
265
|
analysis.security_groups = security_groups
|
265
266
|
progress.advance(task)
|
266
|
-
|
267
|
+
|
267
268
|
# 2. Analyze Network ACLs
|
268
269
|
progress.update(task, description="[security]Analyzing Network ACLs[/security]")
|
269
270
|
nacls = _analyze_network_acls(ec2, vpc_id, analysis)
|
270
271
|
analysis.nacls = nacls
|
271
272
|
progress.advance(task)
|
272
|
-
|
273
|
+
|
273
274
|
# 3. Check VPC Flow Logs
|
274
275
|
progress.update(task, description="[security]Checking VPC Flow Logs[/security]")
|
275
276
|
flow_logs = _analyze_flow_logs(ec2, vpc_id, analysis)
|
276
277
|
analysis.flow_logs = flow_logs
|
277
278
|
progress.advance(task)
|
278
|
-
|
279
|
+
|
279
280
|
# 4. Analyze Route Tables
|
280
281
|
progress.update(task, description="[security]Analyzing Route Tables[/security]")
|
281
282
|
route_tables = _analyze_route_tables(ec2, vpc_id, analysis)
|
282
283
|
analysis.route_tables = route_tables
|
283
284
|
progress.advance(task)
|
284
|
-
|
285
|
+
|
285
286
|
# Log the security analysis
|
286
287
|
logger = get_enhanced_logger("vpc_cleanup")
|
287
288
|
logger.log_vpc_security_analysis(analysis)
|
288
|
-
|
289
|
+
|
289
290
|
# Display results with Rich CLI
|
290
291
|
_display_security_analysis_results(analysis)
|
291
|
-
|
292
|
-
console.print(
|
293
|
-
|
292
|
+
|
293
|
+
console.print(
|
294
|
+
f"{STATUS_INDICATORS['success']} [security]VPC security assessment completed - Risk: {analysis.risk_level.value}[/security]"
|
295
|
+
)
|
296
|
+
|
294
297
|
except ClientError as e:
|
295
298
|
error_msg = f"AWS API error during VPC security assessment: {e}"
|
296
299
|
console.print(f"{STATUS_INDICATORS['error']} [error]{error_msg}[/error]")
|
297
300
|
analysis.add_finding("HIGH", "API Access Error", error_msg, vpc_id)
|
298
|
-
|
301
|
+
|
299
302
|
except Exception as e:
|
300
303
|
error_msg = f"Unexpected error during VPC security assessment: {e}"
|
301
304
|
console.print(f"{STATUS_INDICATORS['error']} [error]{error_msg}[/error]")
|
302
305
|
analysis.add_finding("MEDIUM", "Assessment Error", error_msg, vpc_id)
|
303
|
-
|
306
|
+
|
304
307
|
return analysis
|
305
308
|
|
306
309
|
|
307
|
-
def validate_compliance_requirements(
|
308
|
-
resource_data: Dict[str, Any],
|
309
|
-
frameworks: List[str]
|
310
|
-
) -> Dict[str, bool]:
|
310
|
+
def validate_compliance_requirements(resource_data: Dict[str, Any], frameworks: List[str]) -> Dict[str, bool]:
|
311
311
|
"""
|
312
312
|
Validate resource configuration against compliance frameworks.
|
313
|
-
|
313
|
+
|
314
314
|
Args:
|
315
315
|
resource_data: Resource configuration data to validate
|
316
316
|
frameworks: List of compliance frameworks to check against
|
317
|
-
|
317
|
+
|
318
318
|
Returns:
|
319
319
|
Dict mapping framework names to compliance status (True/False)
|
320
320
|
"""
|
321
321
|
compliance_results = {}
|
322
|
-
|
322
|
+
|
323
323
|
for framework in frameworks:
|
324
324
|
try:
|
325
|
-
framework_enum = ComplianceFramework(framework.upper().replace(
|
325
|
+
framework_enum = ComplianceFramework(framework.upper().replace("-", "_"))
|
326
326
|
compliance_results[framework] = _check_framework_compliance(resource_data, framework_enum)
|
327
327
|
except ValueError:
|
328
|
-
console.print(
|
328
|
+
console.print(
|
329
|
+
f"{STATUS_INDICATORS['warning']} [warning]Unknown compliance framework: {framework}[/warning]"
|
330
|
+
)
|
329
331
|
compliance_results[framework] = False
|
330
|
-
|
332
|
+
|
331
333
|
return compliance_results
|
332
334
|
|
333
335
|
|
334
336
|
def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, Any]:
|
335
337
|
"""
|
336
338
|
Evaluate security baseline from analysis results.
|
337
|
-
|
339
|
+
|
338
340
|
Args:
|
339
341
|
analysis_results: Combined analysis results from VPC assessment
|
340
|
-
|
342
|
+
|
341
343
|
Returns:
|
342
344
|
Security baseline evaluation with recommendations
|
343
345
|
"""
|
@@ -346,25 +348,25 @@ def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, An
|
|
346
348
|
"max_score": 100,
|
347
349
|
"recommendations": [],
|
348
350
|
"critical_findings": [],
|
349
|
-
"compliance_gaps": []
|
351
|
+
"compliance_gaps": [],
|
350
352
|
}
|
351
|
-
|
353
|
+
|
352
354
|
# Security Groups baseline (25 points)
|
353
|
-
sg_score = _evaluate_security_groups_baseline(analysis_results.get(
|
355
|
+
sg_score = _evaluate_security_groups_baseline(analysis_results.get("security_groups", []))
|
354
356
|
baseline_evaluation["baseline_score"] += sg_score
|
355
|
-
|
357
|
+
|
356
358
|
# Network ACLs baseline (25 points)
|
357
|
-
nacl_score = _evaluate_nacls_baseline(analysis_results.get(
|
359
|
+
nacl_score = _evaluate_nacls_baseline(analysis_results.get("nacls", []))
|
358
360
|
baseline_evaluation["baseline_score"] += nacl_score
|
359
|
-
|
361
|
+
|
360
362
|
# Flow Logs baseline (25 points)
|
361
|
-
flow_logs_score = _evaluate_flow_logs_baseline(analysis_results.get(
|
363
|
+
flow_logs_score = _evaluate_flow_logs_baseline(analysis_results.get("flow_logs", []))
|
362
364
|
baseline_evaluation["baseline_score"] += flow_logs_score
|
363
|
-
|
365
|
+
|
364
366
|
# Route Tables baseline (25 points)
|
365
|
-
route_tables_score = _evaluate_route_tables_baseline(analysis_results.get(
|
367
|
+
route_tables_score = _evaluate_route_tables_baseline(analysis_results.get("route_tables", []))
|
366
368
|
baseline_evaluation["baseline_score"] += route_tables_score
|
367
|
-
|
369
|
+
|
368
370
|
# Generate recommendations based on score
|
369
371
|
if baseline_evaluation["baseline_score"] < 70:
|
370
372
|
baseline_evaluation["recommendations"].append("Immediate security review required")
|
@@ -373,27 +375,27 @@ def evaluate_security_baseline(analysis_results: Dict[str, Any]) -> Dict[str, An
|
|
373
375
|
baseline_evaluation["recommendations"].append("Security improvements recommended")
|
374
376
|
else:
|
375
377
|
baseline_evaluation["recommendations"].append("Security posture meets enterprise standards")
|
376
|
-
|
378
|
+
|
377
379
|
return baseline_evaluation
|
378
380
|
|
379
381
|
|
380
382
|
def classify_security_risk(resource_analysis: Dict[str, Any]) -> str:
|
381
383
|
"""
|
382
384
|
Classify security risk level for enterprise decision making.
|
383
|
-
|
385
|
+
|
384
386
|
Args:
|
385
387
|
resource_analysis: Resource security analysis data
|
386
|
-
|
388
|
+
|
387
389
|
Returns:
|
388
390
|
Risk classification: LOW, MEDIUM, HIGH, or CRITICAL
|
389
391
|
"""
|
390
392
|
risk_factors = []
|
391
|
-
|
393
|
+
|
392
394
|
# Check for critical security misconfigurations
|
393
|
-
findings = resource_analysis.get(
|
394
|
-
critical_count = len([f for f in findings if f.get(
|
395
|
-
high_count = len([f for f in findings if f.get(
|
396
|
-
|
395
|
+
findings = resource_analysis.get("findings", [])
|
396
|
+
critical_count = len([f for f in findings if f.get("severity") == "CRITICAL"])
|
397
|
+
high_count = len([f for f in findings if f.get("severity") == "HIGH"])
|
398
|
+
|
397
399
|
if critical_count > 0:
|
398
400
|
return SecurityRiskLevel.CRITICAL.value
|
399
401
|
elif high_count >= 3:
|
@@ -406,29 +408,28 @@ def classify_security_risk(resource_analysis: Dict[str, Any]) -> str:
|
|
406
408
|
|
407
409
|
# Private helper functions for detailed security analysis
|
408
410
|
|
411
|
+
|
409
412
|
def _analyze_security_groups(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
|
410
413
|
"""Analyze Security Groups for security risks."""
|
411
414
|
try:
|
412
|
-
response = ec2_client.describe_security_groups(
|
413
|
-
|
414
|
-
)
|
415
|
-
|
415
|
+
response = ec2_client.describe_security_groups(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
|
416
|
+
|
416
417
|
security_groups = []
|
417
|
-
for sg in response[
|
418
|
+
for sg in response["SecurityGroups"]:
|
418
419
|
sg_analysis = {
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
420
|
+
"group_id": sg["GroupId"],
|
421
|
+
"group_name": sg["GroupName"],
|
422
|
+
"description": sg["Description"],
|
423
|
+
"inbound_rules": sg.get("IpPermissions", []),
|
424
|
+
"outbound_rules": sg.get("IpPermissionsEgress", []),
|
424
425
|
}
|
425
|
-
|
426
|
+
|
426
427
|
# Check for overly permissive rules
|
427
428
|
_check_security_group_rules(sg, analysis)
|
428
429
|
security_groups.append(sg_analysis)
|
429
|
-
|
430
|
+
|
430
431
|
return security_groups
|
431
|
-
|
432
|
+
|
432
433
|
except ClientError as e:
|
433
434
|
analysis.add_finding("MEDIUM", "Security Groups Analysis Failed", str(e), vpc_id)
|
434
435
|
return []
|
@@ -437,32 +438,30 @@ def _analyze_security_groups(ec2_client, vpc_id: str, analysis: VPCSecurityAnaly
|
|
437
438
|
def _analyze_network_acls(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
|
438
439
|
"""Analyze Network ACLs for security configuration."""
|
439
440
|
try:
|
440
|
-
response = ec2_client.describe_network_acls(
|
441
|
-
|
442
|
-
)
|
443
|
-
|
441
|
+
response = ec2_client.describe_network_acls(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
|
442
|
+
|
444
443
|
nacls = []
|
445
|
-
for nacl in response[
|
444
|
+
for nacl in response["NetworkAcls"]:
|
446
445
|
nacl_analysis = {
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
446
|
+
"nacl_id": nacl["NetworkAclId"],
|
447
|
+
"is_default": nacl["IsDefault"],
|
448
|
+
"entries": nacl.get("Entries", []),
|
449
|
+
"associations": nacl.get("Associations", []),
|
451
450
|
}
|
452
|
-
|
451
|
+
|
453
452
|
# Check for default NACL usage (potential security risk)
|
454
|
-
if nacl[
|
453
|
+
if nacl["IsDefault"]:
|
455
454
|
analysis.add_finding(
|
456
|
-
"LOW",
|
455
|
+
"LOW",
|
457
456
|
"Default NACL in use",
|
458
457
|
"Consider creating custom NACLs for better security control",
|
459
|
-
nacl[
|
458
|
+
nacl["NetworkAclId"],
|
460
459
|
)
|
461
|
-
|
460
|
+
|
462
461
|
nacls.append(nacl_analysis)
|
463
|
-
|
462
|
+
|
464
463
|
return nacls
|
465
|
-
|
464
|
+
|
466
465
|
except ClientError as e:
|
467
466
|
analysis.add_finding("MEDIUM", "Network ACLs Analysis Failed", str(e), vpc_id)
|
468
467
|
return []
|
@@ -472,33 +471,30 @@ def _analyze_flow_logs(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -
|
|
472
471
|
"""Check VPC Flow Logs configuration."""
|
473
472
|
try:
|
474
473
|
response = ec2_client.describe_flow_logs(
|
475
|
-
Filters=[
|
476
|
-
{'Name': 'resource-id', 'Values': [vpc_id]},
|
477
|
-
{'Name': 'resource-type', 'Values': ['VPC']}
|
478
|
-
]
|
474
|
+
Filters=[{"Name": "resource-id", "Values": [vpc_id]}, {"Name": "resource-type", "Values": ["VPC"]}]
|
479
475
|
)
|
480
|
-
|
481
|
-
flow_logs = response.get(
|
482
|
-
|
476
|
+
|
477
|
+
flow_logs = response.get("FlowLogs", [])
|
478
|
+
|
483
479
|
if not flow_logs:
|
484
480
|
analysis.add_finding(
|
485
481
|
"MEDIUM",
|
486
482
|
"VPC Flow Logs not enabled",
|
487
483
|
"Enable VPC Flow Logs for network monitoring and security analysis",
|
488
|
-
vpc_id
|
484
|
+
vpc_id,
|
489
485
|
)
|
490
486
|
else:
|
491
487
|
for flow_log in flow_logs:
|
492
|
-
if flow_log[
|
488
|
+
if flow_log["FlowLogStatus"] != "ACTIVE":
|
493
489
|
analysis.add_finding(
|
494
490
|
"MEDIUM",
|
495
491
|
f"Flow Log {flow_log['FlowLogId']} not active",
|
496
492
|
f"Flow Log status: {flow_log['FlowLogStatus']}",
|
497
|
-
flow_log[
|
493
|
+
flow_log["FlowLogId"],
|
498
494
|
)
|
499
|
-
|
500
|
-
return [{
|
501
|
-
|
495
|
+
|
496
|
+
return [{"flow_log_id": fl.get("FlowLogId"), "status": fl.get("FlowLogStatus")} for fl in flow_logs]
|
497
|
+
|
502
498
|
except ClientError as e:
|
503
499
|
analysis.add_finding("MEDIUM", "Flow Logs Analysis Failed", str(e), vpc_id)
|
504
500
|
return []
|
@@ -507,34 +503,32 @@ def _analyze_flow_logs(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -
|
|
507
503
|
def _analyze_route_tables(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis) -> List[Dict[str, Any]]:
|
508
504
|
"""Analyze Route Tables for security implications."""
|
509
505
|
try:
|
510
|
-
response = ec2_client.describe_route_tables(
|
511
|
-
|
512
|
-
)
|
513
|
-
|
506
|
+
response = ec2_client.describe_route_tables(Filters=[{"Name": "vpc-id", "Values": [vpc_id]}])
|
507
|
+
|
514
508
|
route_tables = []
|
515
|
-
for rt in response[
|
509
|
+
for rt in response["RouteTables"]:
|
516
510
|
rt_analysis = {
|
517
|
-
|
518
|
-
|
519
|
-
|
511
|
+
"route_table_id": rt["RouteTableId"],
|
512
|
+
"routes": rt.get("Routes", []),
|
513
|
+
"associations": rt.get("Associations", []),
|
520
514
|
}
|
521
|
-
|
515
|
+
|
522
516
|
# Check for overly broad routes
|
523
|
-
for route in rt.get(
|
524
|
-
if route.get(
|
525
|
-
gateway_id = route.get(
|
526
|
-
if gateway_id.startswith(
|
517
|
+
for route in rt.get("Routes", []):
|
518
|
+
if route.get("DestinationCidrBlock") == "0.0.0.0/0":
|
519
|
+
gateway_id = route.get("GatewayId", "")
|
520
|
+
if gateway_id.startswith("igw-"):
|
527
521
|
analysis.add_finding(
|
528
522
|
"HIGH",
|
529
523
|
"Public route detected",
|
530
524
|
f"Route table {rt['RouteTableId']} has public internet access via {gateway_id}",
|
531
|
-
rt[
|
525
|
+
rt["RouteTableId"],
|
532
526
|
)
|
533
|
-
|
527
|
+
|
534
528
|
route_tables.append(rt_analysis)
|
535
|
-
|
529
|
+
|
536
530
|
return route_tables
|
537
|
-
|
531
|
+
|
538
532
|
except ClientError as e:
|
539
533
|
analysis.add_finding("MEDIUM", "Route Tables Analysis Failed", str(e), vpc_id)
|
540
534
|
return []
|
@@ -542,18 +536,18 @@ def _analyze_route_tables(ec2_client, vpc_id: str, analysis: VPCSecurityAnalysis
|
|
542
536
|
|
543
537
|
def _check_security_group_rules(security_group: Dict[str, Any], analysis: VPCSecurityAnalysis):
|
544
538
|
"""Check Security Group rules for common security issues."""
|
545
|
-
sg_id = security_group[
|
546
|
-
|
539
|
+
sg_id = security_group["GroupId"]
|
540
|
+
|
547
541
|
# Check inbound rules
|
548
|
-
for rule in security_group.get(
|
549
|
-
for ip_range in rule.get(
|
550
|
-
if ip_range.get(
|
542
|
+
for rule in security_group.get("IpPermissions", []):
|
543
|
+
for ip_range in rule.get("IpRanges", []):
|
544
|
+
if ip_range.get("CidrIp") == "0.0.0.0/0":
|
551
545
|
ports = f"{rule.get('FromPort', 'All')}-{rule.get('ToPort', 'All')}"
|
552
546
|
analysis.add_finding(
|
553
547
|
"HIGH",
|
554
548
|
"Overly permissive Security Group",
|
555
549
|
f"Security Group {sg_id} allows inbound access from anywhere (0.0.0.0/0) on ports {ports}",
|
556
|
-
sg_id
|
550
|
+
sg_id,
|
557
551
|
)
|
558
552
|
|
559
553
|
|
@@ -561,40 +555,34 @@ def _check_framework_compliance(resource_data: Dict[str, Any], framework: Compli
|
|
561
555
|
"""Check resource compliance against specific framework."""
|
562
556
|
if framework == ComplianceFramework.SOC2:
|
563
557
|
# SOC2 requires logging and access controls
|
564
|
-
return (
|
565
|
-
resource_data.get('flow_logs_enabled', False) and
|
566
|
-
len(resource_data.get('security_groups', [])) > 0
|
567
|
-
)
|
558
|
+
return resource_data.get("flow_logs_enabled", False) and len(resource_data.get("security_groups", [])) > 0
|
568
559
|
elif framework == ComplianceFramework.PCI_DSS:
|
569
560
|
# PCI-DSS requires strict access controls
|
570
|
-
findings = resource_data.get(
|
571
|
-
high_severity_findings = [f for f in findings if f.get(
|
561
|
+
findings = resource_data.get("findings", [])
|
562
|
+
high_severity_findings = [f for f in findings if f.get("severity") in ["HIGH", "CRITICAL"]]
|
572
563
|
return len(high_severity_findings) == 0
|
573
564
|
elif framework == ComplianceFramework.HIPAA:
|
574
565
|
# HIPAA requires encryption and access logging
|
575
|
-
return (
|
576
|
-
resource_data.get('flow_logs_enabled', False) and
|
577
|
-
resource_data.get('baseline_score', 0) >= 85
|
578
|
-
)
|
566
|
+
return resource_data.get("flow_logs_enabled", False) and resource_data.get("baseline_score", 0) >= 85
|
579
567
|
else:
|
580
568
|
# Default compliance check
|
581
|
-
return resource_data.get(
|
569
|
+
return resource_data.get("baseline_score", 0) >= 70
|
582
570
|
|
583
571
|
|
584
572
|
def _evaluate_security_groups_baseline(security_groups: List[Dict[str, Any]]) -> int:
|
585
573
|
"""Evaluate Security Groups against security baseline (max 25 points)."""
|
586
574
|
if not security_groups:
|
587
575
|
return 0
|
588
|
-
|
576
|
+
|
589
577
|
score = 25
|
590
578
|
for sg in security_groups:
|
591
579
|
# Check for overly permissive rules
|
592
|
-
inbound_rules = sg.get(
|
580
|
+
inbound_rules = sg.get("inbound_rules", [])
|
593
581
|
for rule in inbound_rules:
|
594
|
-
for ip_range in rule.get(
|
595
|
-
if ip_range.get(
|
582
|
+
for ip_range in rule.get("IpRanges", []):
|
583
|
+
if ip_range.get("CidrIp") == "0.0.0.0/0":
|
596
584
|
score -= 5 # Deduct points for open access
|
597
|
-
|
585
|
+
|
598
586
|
return max(0, score)
|
599
587
|
|
600
588
|
|
@@ -602,12 +590,12 @@ def _evaluate_nacls_baseline(nacls: List[Dict[str, Any]]) -> int:
|
|
602
590
|
"""Evaluate Network ACLs against security baseline (max 25 points)."""
|
603
591
|
if not nacls:
|
604
592
|
return 10 # Partial score for having no custom NACLs
|
605
|
-
|
593
|
+
|
606
594
|
score = 25
|
607
|
-
default_nacl_count = len([n for n in nacls if n.get(
|
595
|
+
default_nacl_count = len([n for n in nacls if n.get("is_default", False)])
|
608
596
|
if default_nacl_count > 0:
|
609
597
|
score -= 5 # Deduct for using default NACLs
|
610
|
-
|
598
|
+
|
611
599
|
return max(10, score)
|
612
600
|
|
613
601
|
|
@@ -615,8 +603,8 @@ def _evaluate_flow_logs_baseline(flow_logs: List[Dict[str, Any]]) -> int:
|
|
615
603
|
"""Evaluate Flow Logs against security baseline (max 25 points)."""
|
616
604
|
if not flow_logs:
|
617
605
|
return 0 # No flow logs = no points
|
618
|
-
|
619
|
-
active_flow_logs = len([fl for fl in flow_logs if fl.get(
|
606
|
+
|
607
|
+
active_flow_logs = len([fl for fl in flow_logs if fl.get("status") == "ACTIVE"])
|
620
608
|
return 25 if active_flow_logs > 0 else 10
|
621
609
|
|
622
610
|
|
@@ -624,37 +612,36 @@ def _evaluate_route_tables_baseline(route_tables: List[Dict[str, Any]]) -> int:
|
|
624
612
|
"""Evaluate Route Tables against security baseline (max 25 points)."""
|
625
613
|
if not route_tables:
|
626
614
|
return 0
|
627
|
-
|
615
|
+
|
628
616
|
score = 25
|
629
617
|
for rt in route_tables:
|
630
|
-
for route in rt.get(
|
631
|
-
if
|
632
|
-
route.get('GatewayId', '').startswith('igw-')):
|
618
|
+
for route in rt.get("routes", []):
|
619
|
+
if route.get("DestinationCidrBlock") == "0.0.0.0/0" and route.get("GatewayId", "").startswith("igw-"):
|
633
620
|
score -= 3 # Deduct for public routes
|
634
|
-
|
621
|
+
|
635
622
|
return max(15, score)
|
636
623
|
|
637
624
|
|
638
625
|
def _display_security_analysis_results(analysis: VPCSecurityAnalysis):
|
639
626
|
"""Display security analysis results with Rich CLI formatting."""
|
640
|
-
|
627
|
+
|
641
628
|
# Create summary table
|
642
629
|
table = create_table(
|
643
630
|
title=f"VPC Security Analysis - {analysis.vpc_id}",
|
644
631
|
columns=[
|
645
632
|
{"name": "Component", "style": "cyan"},
|
646
633
|
{"name": "Count", "style": "white"},
|
647
|
-
{"name": "Status", "style": "green"}
|
648
|
-
]
|
634
|
+
{"name": "Status", "style": "green"},
|
635
|
+
],
|
649
636
|
)
|
650
|
-
|
637
|
+
|
651
638
|
table.add_row("Security Groups", str(len(analysis.security_groups)), "✅ Analyzed")
|
652
639
|
table.add_row("Network ACLs", str(len(analysis.nacls)), "✅ Analyzed")
|
653
640
|
table.add_row("Flow Logs", str(len(analysis.flow_logs)), "✅ Checked" if analysis.flow_logs else "❌ Missing")
|
654
641
|
table.add_row("Route Tables", str(len(analysis.route_tables)), "✅ Analyzed")
|
655
|
-
|
642
|
+
|
656
643
|
console.print(table)
|
657
|
-
|
644
|
+
|
658
645
|
# Display findings if any
|
659
646
|
if analysis.findings:
|
660
647
|
findings_table = create_table(
|
@@ -662,47 +649,43 @@ def _display_security_analysis_results(analysis: VPCSecurityAnalysis):
|
|
662
649
|
columns=[
|
663
650
|
{"name": "Severity", "style": "red bold"},
|
664
651
|
{"name": "Finding", "style": "yellow"},
|
665
|
-
{"name": "Resource", "style": "cyan"}
|
666
|
-
]
|
652
|
+
{"name": "Resource", "style": "cyan"},
|
653
|
+
],
|
667
654
|
)
|
668
|
-
|
655
|
+
|
669
656
|
for finding in analysis.findings:
|
670
|
-
findings_table.add_row(
|
671
|
-
|
672
|
-
finding['title'],
|
673
|
-
finding['resource']
|
674
|
-
)
|
675
|
-
|
657
|
+
findings_table.add_row(finding["severity"], finding["title"], finding["resource"])
|
658
|
+
|
676
659
|
console.print(findings_table)
|
677
|
-
|
660
|
+
|
678
661
|
# Risk level summary
|
679
662
|
risk_style = {
|
680
663
|
SecurityRiskLevel.LOW: "green",
|
681
|
-
SecurityRiskLevel.MEDIUM: "yellow",
|
664
|
+
SecurityRiskLevel.MEDIUM: "yellow",
|
682
665
|
SecurityRiskLevel.HIGH: "red",
|
683
|
-
SecurityRiskLevel.CRITICAL: "red bold"
|
666
|
+
SecurityRiskLevel.CRITICAL: "red bold",
|
684
667
|
}.get(analysis.risk_level, "white")
|
685
|
-
|
668
|
+
|
686
669
|
risk_panel = create_panel(
|
687
670
|
f"Overall Security Risk: [{risk_style}]{analysis.risk_level.value}[/{risk_style}]\n"
|
688
671
|
f"Findings: {len(analysis.findings)}\n"
|
689
672
|
f"Analysis Time: {analysis.timestamp.strftime('%Y-%m-%d %H:%M:%S UTC')}",
|
690
673
|
title="[security]Security Risk Assessment[/security]",
|
691
|
-
border_style=risk_style
|
674
|
+
border_style=risk_style,
|
692
675
|
)
|
693
|
-
|
676
|
+
|
694
677
|
console.print(risk_panel)
|
695
678
|
|
696
679
|
|
697
680
|
# Export the main functions needed by VPC cleanup and other modules
|
698
681
|
__all__ = [
|
699
682
|
"get_enhanced_logger",
|
700
|
-
"assess_vpc_security_posture",
|
683
|
+
"assess_vpc_security_posture",
|
701
684
|
"validate_compliance_requirements",
|
702
685
|
"evaluate_security_baseline",
|
703
686
|
"classify_security_risk",
|
704
687
|
"SecurityRiskLevel",
|
705
688
|
"ComplianceFramework",
|
706
689
|
"VPCSecurityAnalysis",
|
707
|
-
"EnterpriseSecurityLogger"
|
708
|
-
]
|
690
|
+
"EnterpriseSecurityLogger",
|
691
|
+
]
|