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
@@ -24,8 +24,9 @@ logger = logging.getLogger(__name__)
24
24
  @dataclass
25
25
  class AccountSession:
26
26
  """Represents a cross-account session with metadata"""
27
+
27
28
  account_id: str
28
- account_name: Optional[str]
29
+ account_name: Optional[str]
29
30
  session: boto3.Session
30
31
  status: str
31
32
  error_message: Optional[str] = None
@@ -34,68 +35,67 @@ class AccountSession:
34
35
  def create_multi_profile_sessions(profiles: List[str]) -> List[AccountSession]:
35
36
  """
36
37
  Create sessions using direct profile access for organizations without cross-account roles.
37
-
38
+
38
39
  This is an alternative approach when OrganizationAccountAccessRole is not available.
39
40
  Uses environment variables like CENTRALISED_OPS_PROFILE, BILLING_PROFILE, etc.
40
-
41
+
41
42
  Args:
42
43
  profiles: List of AWS profile names to use
43
-
44
+
44
45
  Returns:
45
46
  List of AccountSession objects with successful and failed sessions
46
47
  """
47
48
  import os
48
-
49
+
49
50
  print_info(f"🌐 Creating sessions for {len(profiles)} profiles")
50
51
  account_sessions = []
51
-
52
+
52
53
  for profile_name in profiles:
53
54
  try:
54
55
  # Validate profile exists and is accessible
55
56
  session = boto3.Session(profile_name=profile_name)
56
- sts_client = session.client('sts')
57
+ sts_client = session.client("sts")
57
58
  identity = sts_client.get_caller_identity()
58
-
59
- account_id = identity['Account']
60
-
59
+
60
+ account_id = identity["Account"]
61
+
61
62
  # Try to get account name from Organizations if possible
62
63
  account_name = profile_name # Default to profile name
63
64
  try:
64
- orgs_client = session.client('organizations')
65
+ orgs_client = session.client("organizations")
65
66
  account_info = orgs_client.describe_account(AccountId=account_id)
66
- account_name = account_info['Account']['Name']
67
+ account_name = account_info["Account"]["Name"]
67
68
  except:
68
69
  pass # Use profile name as fallback
69
-
70
- account_sessions.append(AccountSession(
71
- account_id=account_id,
72
- account_name=account_name,
73
- session=session,
74
- status="success"
75
- ))
76
-
70
+
71
+ account_sessions.append(
72
+ AccountSession(account_id=account_id, account_name=account_name, session=session, status="success")
73
+ )
74
+
77
75
  print_success(f"✅ Session created for {account_id} using profile {profile_name}")
78
-
76
+
79
77
  except Exception as e:
80
78
  print_warning(f"⚠️ Failed to create session for profile {profile_name}: {e}")
81
- account_sessions.append(AccountSession(
82
- account_id=profile_name, # Use profile name as ID when we can't get real ID
83
- account_name=profile_name,
84
- session=None,
85
- status="failed",
86
- error_message=str(e)
87
- ))
88
-
79
+ account_sessions.append(
80
+ AccountSession(
81
+ account_id=profile_name, # Use profile name as ID when we can't get real ID
82
+ account_name=profile_name,
83
+ session=None,
84
+ status="failed",
85
+ error_message=str(e),
86
+ )
87
+ )
88
+
89
89
  return account_sessions
90
90
 
91
91
 
92
92
  class CrossAccountSessionManager:
93
93
  """
94
94
  Enterprise cross-account session manager using STS AssumeRole pattern.
95
-
95
+
96
96
  This replaces the broken profile@accountId format with proper STS AssumeRole
97
97
  for multi-account VPC discovery across Landing Zone accounts.
98
-
98
+
99
99
  Key Features:
100
100
  - Uses CENTRALISED_OPS_PROFILE as base session for assuming roles
101
101
  - Standard OrganizationAccountAccessRole assumption
@@ -103,91 +103,94 @@ class CrossAccountSessionManager:
103
103
  - Comprehensive error handling and graceful degradation
104
104
  - Compatible with existing VPC module architecture
105
105
  """
106
-
106
+
107
107
  def __init__(self, base_profile: str, role_name: str = "OrganizationAccountAccessRole"):
108
108
  """
109
109
  Initialize cross-account session manager.
110
-
110
+
111
111
  Args:
112
112
  base_profile: Base profile (e.g., CENTRALISED_OPS_PROFILE) for assuming roles
113
113
  role_name: IAM role name to assume in target accounts
114
114
  """
115
115
  self.base_profile = base_profile
116
116
  self.role_name = role_name
117
-
117
+
118
118
  # Use management session for cross-account role assumptions
119
119
  # Management account has the trust relationships for OrganizationAccountAccessRole
120
- self.session = create_management_session(profile=base_profile)
121
-
120
+ self.session = create_management_session(profile_name=base_profile)
121
+
122
122
  print_info(f"🔐 Cross-account session manager initialized with {base_profile}")
123
-
123
+
124
124
  def create_cross_account_sessions(
125
- self,
126
- accounts: List[Dict[str, str]],
127
- max_workers: int = 10
125
+ self, accounts: List[Dict[str, str]], max_workers: int = 10
128
126
  ) -> List[AccountSession]:
129
127
  """
130
128
  Create cross-account sessions using STS AssumeRole pattern.
131
-
129
+
132
130
  Args:
133
131
  accounts: List of account dictionaries from Organizations API
134
132
  max_workers: Maximum parallel workers for session creation
135
-
133
+
136
134
  Returns:
137
135
  List of AccountSession objects with successful and failed sessions
138
136
  """
139
137
  print_info(f"🌐 Creating cross-account sessions for {len(accounts)} accounts")
140
-
138
+
141
139
  account_sessions = []
142
-
140
+
143
141
  # Filter active accounts only
144
142
  active_accounts = [acc for acc in accounts if acc.get("status") == "ACTIVE"]
145
143
  print_info(f"📋 Processing {len(active_accounts)} active accounts")
146
-
144
+
147
145
  # Create sessions in parallel for performance
148
146
  with ThreadPoolExecutor(max_workers=max_workers) as executor:
149
147
  future_to_account = {
150
- executor.submit(self._create_account_session, account): account
151
- for account in active_accounts
148
+ executor.submit(self._create_account_session, account): account for account in active_accounts
152
149
  }
153
-
150
+
154
151
  for future in as_completed(future_to_account):
155
152
  account = future_to_account[future]
156
153
  try:
157
154
  account_session = future.result()
158
155
  account_sessions.append(account_session)
159
-
156
+
160
157
  if account_session.status == "success":
161
158
  print_success(f"✅ Session created for {account_session.account_id}")
162
159
  else:
163
- print_warning(f"⚠️ Session failed for {account_session.account_id}: {account_session.error_message}")
164
-
160
+ print_warning(
161
+ f"⚠️ Session failed for {account_session.account_id}: {account_session.error_message}"
162
+ )
163
+
165
164
  except Exception as e:
166
165
  print_error(f"❌ Unexpected error creating session for {account['id']}: {e}")
167
- account_sessions.append(AccountSession(
168
- account_id=account["id"],
169
- account_name=account.get("name"),
170
- session=None,
171
- status="error",
172
- error_message=str(e)
173
- ))
174
-
166
+ account_sessions.append(
167
+ AccountSession(
168
+ account_id=account["id"],
169
+ account_name=account.get("name"),
170
+ session=None,
171
+ status="error",
172
+ error_message=str(e),
173
+ )
174
+ )
175
+
175
176
  successful_sessions = [s for s in account_sessions if s.status == "success"]
176
177
  failed_sessions = [s for s in account_sessions if s.status != "success"]
177
-
178
- print_info(f"🎯 Session creation complete: {len(successful_sessions)} successful, {len(failed_sessions)} failed")
179
-
178
+
179
+ print_info(
180
+ f"🎯 Session creation complete: {len(successful_sessions)} successful, {len(failed_sessions)} failed"
181
+ )
182
+
180
183
  return account_sessions
181
-
184
+
182
185
  def _create_account_session(self, account: Dict[str, str]) -> AccountSession:
183
186
  """
184
187
  Create a session for a single account using STS AssumeRole.
185
-
188
+
186
189
  This is the core implementation of the enterprise pattern.
187
190
  """
188
191
  account_id = account["id"]
189
192
  account_name = account.get("name", f"Account-{account_id}")
190
-
193
+
191
194
  # Try multiple role patterns for different organization setups - universal compatibility
192
195
  role_patterns = [
193
196
  self.role_name, # Default: OrganizationAccountAccessRole
@@ -199,87 +202,80 @@ class CrossAccountSessionManager:
199
202
  "CrossAccountRole", # Generic cross-account role
200
203
  "AssumeRole", # Generic assume role
201
204
  ]
202
-
205
+
203
206
  for role_name in role_patterns:
204
207
  try:
205
208
  # Step 1: Assume role in target account using STS
206
- sts_client = self.session.client('sts')
209
+ sts_client = self.session.client("sts")
207
210
  assumed_role = sts_client.assume_role(
208
211
  RoleArn=f"arn:aws:iam::{account_id}:role/{role_name}",
209
- RoleSessionName=f"VPCDiscovery-{account_id[:12]}"
212
+ RoleSessionName=f"VPCDiscovery-{account_id[:12]}",
210
213
  )
211
-
214
+
212
215
  # If successful, continue with this role
213
-
216
+
214
217
  # Step 2: Create session with assumed role credentials
215
218
  assumed_session = boto3.Session(
216
- aws_access_key_id=assumed_role['Credentials']['AccessKeyId'],
217
- aws_secret_access_key=assumed_role['Credentials']['SecretAccessKey'],
218
- aws_session_token=assumed_role['Credentials']['SessionToken']
219
+ aws_access_key_id=assumed_role["Credentials"]["AccessKeyId"],
220
+ aws_secret_access_key=assumed_role["Credentials"]["SecretAccessKey"],
221
+ aws_session_token=assumed_role["Credentials"]["SessionToken"],
219
222
  )
220
-
223
+
221
224
  # Step 3: Validate session with basic STS call
222
- assumed_sts = assumed_session.client('sts')
225
+ assumed_sts = assumed_session.client("sts")
223
226
  identity = assumed_sts.get_caller_identity()
224
-
225
- logger.debug(f"Successfully assumed role {role_name} in account {account_id}, identity: {identity['Arn']}")
226
-
227
+
228
+ logger.debug(
229
+ f"Successfully assumed role {role_name} in account {account_id}, identity: {identity['Arn']}"
230
+ )
231
+
227
232
  return AccountSession(
228
- account_id=account_id,
229
- account_name=account_name,
230
- session=assumed_session,
231
- status="success"
233
+ account_id=account_id, account_name=account_name, session=assumed_session, status="success"
232
234
  )
233
-
235
+
234
236
  except ClientError as e:
235
237
  # Continue to next role pattern
236
238
  continue
237
-
239
+
238
240
  # If no role patterns worked, return failure
239
241
  error_msg = f"Unable to assume any role pattern in {account_id} - tried: {', '.join(role_patterns)}"
240
242
  logger.warning(f"Failed to create session for {account_id}: {error_msg}")
241
-
243
+
242
244
  return AccountSession(
243
- account_id=account_id,
244
- account_name=account_name,
245
- session=None,
246
- status="failed",
247
- error_message=error_msg
245
+ account_id=account_id, account_name=account_name, session=None, status="failed", error_message=error_msg
248
246
  )
249
-
247
+
250
248
  def get_successful_sessions(self, account_sessions: List[AccountSession]) -> List[AccountSession]:
251
249
  """Get only successful account sessions for VPC discovery."""
252
250
  successful = [s for s in account_sessions if s.status == "success"]
253
251
  print_info(f"🎯 {len(successful)} accounts ready for VPC discovery")
254
252
  return successful
255
-
253
+
256
254
  def get_session_summary(self, account_sessions: List[AccountSession]) -> Dict[str, int]:
257
255
  """Get summary statistics for session creation."""
258
256
  summary = {
259
257
  "total": len(account_sessions),
260
258
  "successful": len([s for s in account_sessions if s.status == "success"]),
261
259
  "failed": len([s for s in account_sessions if s.status == "failed"]),
262
- "errors": len([s for s in account_sessions if s.status == "error"])
260
+ "errors": len([s for s in account_sessions if s.status == "error"]),
263
261
  }
264
262
  return summary
265
263
 
266
264
 
267
265
  def create_cross_account_vpc_sessions(
268
- accounts: List[Dict[str, str]],
269
- base_profile: str,
270
- role_name: str = "OrganizationAccountAccessRole"
266
+ accounts: List[Dict[str, str]], base_profile: str, role_name: str = "OrganizationAccountAccessRole"
271
267
  ) -> List[AccountSession]:
272
268
  """
273
269
  Convenience function to create cross-account VPC sessions.
274
-
270
+
275
271
  This is the main entry point for VPC modules to replace the broken
276
272
  profile@accountId pattern with proper STS AssumeRole.
277
-
273
+
278
274
  Args:
279
275
  accounts: List of organization accounts from get_organization_accounts
280
276
  base_profile: Base profile for assuming roles (CENTRALISED_OPS_PROFILE)
281
277
  role_name: IAM role name to assume
282
-
278
+
283
279
  Returns:
284
280
  List of AccountSession objects ready for VPC discovery
285
281
  """
@@ -289,24 +285,23 @@ def create_cross_account_vpc_sessions(
289
285
 
290
286
  # Compatibility functions for existing VPC module integration
291
287
  def convert_accounts_to_sessions(
292
- accounts: List[Dict[str, str]],
293
- base_profile: str
288
+ accounts: List[Dict[str, str]], base_profile: str
294
289
  ) -> Tuple[List[AccountSession], Dict[str, Dict[str, str]]]:
295
290
  """
296
291
  Convert organization accounts to cross-account sessions.
297
-
292
+
298
293
  This replaces the broken convert_accounts_to_profiles function
299
294
  with proper STS AssumeRole session creation.
300
-
295
+
301
296
  Returns:
302
297
  Tuple of (successful_sessions, account_metadata)
303
298
  """
304
299
  account_sessions = create_cross_account_vpc_sessions(accounts, base_profile)
305
300
  successful_sessions = [s for s in account_sessions if s.status == "success"]
306
-
301
+
307
302
  # Create account metadata dict for compatibility
308
303
  account_metadata = {}
309
304
  for account in accounts:
310
305
  account_metadata[account["id"]] = account
311
-
312
- return successful_sessions, account_metadata
306
+
307
+ return successful_sessions, account_metadata