runbooks 0.2.5__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. conftest.py +26 -0
  2. jupyter-agent/.env +2 -0
  3. jupyter-agent/.env.template +2 -0
  4. jupyter-agent/.gitattributes +35 -0
  5. jupyter-agent/.gradio/certificate.pem +31 -0
  6. jupyter-agent/README.md +16 -0
  7. jupyter-agent/__main__.log +8 -0
  8. jupyter-agent/app.py +256 -0
  9. jupyter-agent/cloudops-agent.png +0 -0
  10. jupyter-agent/ds-system-prompt.txt +154 -0
  11. jupyter-agent/jupyter-agent.png +0 -0
  12. jupyter-agent/llama3_template.jinja +123 -0
  13. jupyter-agent/requirements.txt +9 -0
  14. jupyter-agent/tmp/4ojbs8a02ir/jupyter-agent.ipynb +68 -0
  15. jupyter-agent/tmp/cm5iasgpm3p/jupyter-agent.ipynb +91 -0
  16. jupyter-agent/tmp/crqbsseag5/jupyter-agent.ipynb +91 -0
  17. jupyter-agent/tmp/hohanq1u097/jupyter-agent.ipynb +57 -0
  18. jupyter-agent/tmp/jns1sam29wm/jupyter-agent.ipynb +53 -0
  19. jupyter-agent/tmp/jupyter-agent.ipynb +27 -0
  20. jupyter-agent/utils.py +409 -0
  21. runbooks/__init__.py +71 -3
  22. runbooks/__main__.py +13 -0
  23. runbooks/aws/ec2_describe_instances.py +1 -1
  24. runbooks/aws/ec2_run_instances.py +8 -2
  25. runbooks/aws/ec2_start_stop_instances.py +17 -4
  26. runbooks/aws/ec2_unused_volumes.py +5 -1
  27. runbooks/aws/s3_create_bucket.py +4 -2
  28. runbooks/aws/s3_list_objects.py +6 -1
  29. runbooks/aws/tagging_lambda_handler.py +13 -2
  30. runbooks/aws/tags.json +12 -0
  31. runbooks/base.py +353 -0
  32. runbooks/cfat/README.md +49 -0
  33. runbooks/cfat/__init__.py +74 -0
  34. runbooks/cfat/app.ts +644 -0
  35. runbooks/cfat/assessment/__init__.py +40 -0
  36. runbooks/cfat/assessment/asana-import.csv +39 -0
  37. runbooks/cfat/assessment/cfat-checks.csv +31 -0
  38. runbooks/cfat/assessment/cfat.txt +520 -0
  39. runbooks/cfat/assessment/collectors.py +200 -0
  40. runbooks/cfat/assessment/jira-import.csv +39 -0
  41. runbooks/cfat/assessment/runner.py +387 -0
  42. runbooks/cfat/assessment/validators.py +290 -0
  43. runbooks/cfat/cli.py +103 -0
  44. runbooks/cfat/docs/asana-import.csv +24 -0
  45. runbooks/cfat/docs/cfat-checks.csv +31 -0
  46. runbooks/cfat/docs/cfat.txt +335 -0
  47. runbooks/cfat/docs/checks-output.png +0 -0
  48. runbooks/cfat/docs/cloudshell-console-run.png +0 -0
  49. runbooks/cfat/docs/cloudshell-download.png +0 -0
  50. runbooks/cfat/docs/cloudshell-output.png +0 -0
  51. runbooks/cfat/docs/downloadfile.png +0 -0
  52. runbooks/cfat/docs/jira-import.csv +24 -0
  53. runbooks/cfat/docs/open-cloudshell.png +0 -0
  54. runbooks/cfat/docs/report-header.png +0 -0
  55. runbooks/cfat/models.py +1026 -0
  56. runbooks/cfat/package-lock.json +5116 -0
  57. runbooks/cfat/package.json +38 -0
  58. runbooks/cfat/report.py +496 -0
  59. runbooks/cfat/reporting/__init__.py +46 -0
  60. runbooks/cfat/reporting/exporters.py +337 -0
  61. runbooks/cfat/reporting/formatters.py +496 -0
  62. runbooks/cfat/reporting/templates.py +135 -0
  63. runbooks/cfat/run-assessment.sh +23 -0
  64. runbooks/cfat/runner.py +69 -0
  65. runbooks/cfat/src/actions/check-cloudtrail-existence.ts +43 -0
  66. runbooks/cfat/src/actions/check-config-existence.ts +37 -0
  67. runbooks/cfat/src/actions/check-control-tower.ts +37 -0
  68. runbooks/cfat/src/actions/check-ec2-existence.ts +46 -0
  69. runbooks/cfat/src/actions/check-iam-users.ts +50 -0
  70. runbooks/cfat/src/actions/check-legacy-cur.ts +30 -0
  71. runbooks/cfat/src/actions/check-org-cloudformation.ts +30 -0
  72. runbooks/cfat/src/actions/check-vpc-existence.ts +43 -0
  73. runbooks/cfat/src/actions/create-asanaimport.ts +14 -0
  74. runbooks/cfat/src/actions/create-backlog.ts +372 -0
  75. runbooks/cfat/src/actions/create-jiraimport.ts +15 -0
  76. runbooks/cfat/src/actions/create-report.ts +616 -0
  77. runbooks/cfat/src/actions/define-account-type.ts +51 -0
  78. runbooks/cfat/src/actions/get-enabled-org-policy-types.ts +40 -0
  79. runbooks/cfat/src/actions/get-enabled-org-services.ts +26 -0
  80. runbooks/cfat/src/actions/get-idc-info.ts +34 -0
  81. runbooks/cfat/src/actions/get-org-da-accounts.ts +34 -0
  82. runbooks/cfat/src/actions/get-org-details.ts +35 -0
  83. runbooks/cfat/src/actions/get-org-member-accounts.ts +44 -0
  84. runbooks/cfat/src/actions/get-org-ous.ts +35 -0
  85. runbooks/cfat/src/actions/get-regions.ts +22 -0
  86. runbooks/cfat/src/actions/zip-assessment.ts +27 -0
  87. runbooks/cfat/src/types/index.d.ts +147 -0
  88. runbooks/cfat/tests/__init__.py +141 -0
  89. runbooks/cfat/tests/test_cli.py +340 -0
  90. runbooks/cfat/tests/test_integration.py +290 -0
  91. runbooks/cfat/tests/test_models.py +505 -0
  92. runbooks/cfat/tests/test_reporting.py +354 -0
  93. runbooks/cfat/tsconfig.json +16 -0
  94. runbooks/cfat/webpack.config.cjs +27 -0
  95. runbooks/config.py +260 -0
  96. runbooks/finops/README.md +337 -0
  97. runbooks/finops/__init__.py +86 -0
  98. runbooks/finops/aws_client.py +245 -0
  99. runbooks/finops/cli.py +151 -0
  100. runbooks/finops/cost_processor.py +410 -0
  101. runbooks/finops/dashboard_runner.py +448 -0
  102. runbooks/finops/helpers.py +355 -0
  103. runbooks/finops/main.py +14 -0
  104. runbooks/finops/profile_processor.py +174 -0
  105. runbooks/finops/types.py +66 -0
  106. runbooks/finops/visualisations.py +80 -0
  107. runbooks/inventory/.gitignore +354 -0
  108. runbooks/inventory/ArgumentsClass.py +261 -0
  109. runbooks/inventory/FAILED_SCRIPTS_TROUBLESHOOTING.md +619 -0
  110. runbooks/inventory/Inventory_Modules.py +6130 -0
  111. runbooks/inventory/LandingZone/delete_lz.py +1075 -0
  112. runbooks/inventory/PASSED_SCRIPTS_GUIDE.md +738 -0
  113. runbooks/inventory/README.md +1320 -0
  114. runbooks/inventory/__init__.py +62 -0
  115. runbooks/inventory/account_class.py +532 -0
  116. runbooks/inventory/all_my_instances_wrapper.py +123 -0
  117. runbooks/inventory/aws_decorators.py +201 -0
  118. runbooks/inventory/aws_organization.png +0 -0
  119. runbooks/inventory/cfn_move_stack_instances.py +1526 -0
  120. runbooks/inventory/check_cloudtrail_compliance.py +614 -0
  121. runbooks/inventory/check_controltower_readiness.py +1107 -0
  122. runbooks/inventory/check_landingzone_readiness.py +711 -0
  123. runbooks/inventory/cloudtrail.md +727 -0
  124. runbooks/inventory/collectors/__init__.py +20 -0
  125. runbooks/inventory/collectors/aws_compute.py +518 -0
  126. runbooks/inventory/collectors/aws_networking.py +275 -0
  127. runbooks/inventory/collectors/base.py +222 -0
  128. runbooks/inventory/core/__init__.py +19 -0
  129. runbooks/inventory/core/collector.py +303 -0
  130. runbooks/inventory/core/formatter.py +296 -0
  131. runbooks/inventory/delete_s3_buckets_objects.py +169 -0
  132. runbooks/inventory/discovery.md +81 -0
  133. runbooks/inventory/draw_org_structure.py +748 -0
  134. runbooks/inventory/ec2_vpc_utils.py +341 -0
  135. runbooks/inventory/find_cfn_drift_detection.py +272 -0
  136. runbooks/inventory/find_cfn_orphaned_stacks.py +719 -0
  137. runbooks/inventory/find_cfn_stackset_drift.py +733 -0
  138. runbooks/inventory/find_ec2_security_groups.py +669 -0
  139. runbooks/inventory/find_landingzone_versions.py +201 -0
  140. runbooks/inventory/find_vpc_flow_logs.py +1221 -0
  141. runbooks/inventory/inventory.sh +659 -0
  142. runbooks/inventory/list_cfn_stacks.py +558 -0
  143. runbooks/inventory/list_cfn_stackset_operation_results.py +252 -0
  144. runbooks/inventory/list_cfn_stackset_operations.py +734 -0
  145. runbooks/inventory/list_cfn_stacksets.py +453 -0
  146. runbooks/inventory/list_config_recorders_delivery_channels.py +681 -0
  147. runbooks/inventory/list_ds_directories.py +354 -0
  148. runbooks/inventory/list_ec2_availability_zones.py +286 -0
  149. runbooks/inventory/list_ec2_ebs_volumes.py +244 -0
  150. runbooks/inventory/list_ec2_instances.py +425 -0
  151. runbooks/inventory/list_ecs_clusters_and_tasks.py +562 -0
  152. runbooks/inventory/list_elbs_load_balancers.py +411 -0
  153. runbooks/inventory/list_enis_network_interfaces.py +526 -0
  154. runbooks/inventory/list_guardduty_detectors.py +568 -0
  155. runbooks/inventory/list_iam_policies.py +404 -0
  156. runbooks/inventory/list_iam_roles.py +518 -0
  157. runbooks/inventory/list_iam_saml_providers.py +359 -0
  158. runbooks/inventory/list_lambda_functions.py +882 -0
  159. runbooks/inventory/list_org_accounts.py +446 -0
  160. runbooks/inventory/list_org_accounts_users.py +354 -0
  161. runbooks/inventory/list_rds_db_instances.py +406 -0
  162. runbooks/inventory/list_route53_hosted_zones.py +318 -0
  163. runbooks/inventory/list_servicecatalog_provisioned_products.py +575 -0
  164. runbooks/inventory/list_sns_topics.py +360 -0
  165. runbooks/inventory/list_ssm_parameters.py +402 -0
  166. runbooks/inventory/list_vpc_subnets.py +433 -0
  167. runbooks/inventory/list_vpcs.py +422 -0
  168. runbooks/inventory/lockdown_cfn_stackset_role.py +224 -0
  169. runbooks/inventory/models/__init__.py +24 -0
  170. runbooks/inventory/models/account.py +192 -0
  171. runbooks/inventory/models/inventory.py +309 -0
  172. runbooks/inventory/models/resource.py +247 -0
  173. runbooks/inventory/recover_cfn_stack_ids.py +205 -0
  174. runbooks/inventory/requirements.txt +12 -0
  175. runbooks/inventory/run_on_multi_accounts.py +211 -0
  176. runbooks/inventory/tests/common_test_data.py +3661 -0
  177. runbooks/inventory/tests/common_test_functions.py +204 -0
  178. runbooks/inventory/tests/setup.py +24 -0
  179. runbooks/inventory/tests/src.py +18 -0
  180. runbooks/inventory/tests/test_cfn_describe_stacks.py +208 -0
  181. runbooks/inventory/tests/test_ec2_describe_instances.py +162 -0
  182. runbooks/inventory/tests/test_inventory_modules.py +55 -0
  183. runbooks/inventory/tests/test_lambda_list_functions.py +86 -0
  184. runbooks/inventory/tests/test_moto_integration_example.py +273 -0
  185. runbooks/inventory/tests/test_org_list_accounts.py +49 -0
  186. runbooks/inventory/update_aws_actions.py +173 -0
  187. runbooks/inventory/update_cfn_stacksets.py +1215 -0
  188. runbooks/inventory/update_cloudwatch_logs_retention_policy.py +294 -0
  189. runbooks/inventory/update_iam_roles_cross_accounts.py +478 -0
  190. runbooks/inventory/update_s3_public_access_block.py +539 -0
  191. runbooks/inventory/utils/__init__.py +23 -0
  192. runbooks/inventory/utils/aws_helpers.py +510 -0
  193. runbooks/inventory/utils/threading_utils.py +493 -0
  194. runbooks/inventory/utils/validation.py +682 -0
  195. runbooks/inventory/verify_ec2_security_groups.py +1430 -0
  196. runbooks/main.py +1004 -0
  197. runbooks/organizations/__init__.py +12 -0
  198. runbooks/organizations/manager.py +374 -0
  199. runbooks/security/README.md +447 -0
  200. runbooks/security/__init__.py +71 -0
  201. runbooks/{security_baseline → security}/checklist/alternate_contacts.py +8 -1
  202. runbooks/{security_baseline → security}/checklist/bucket_public_access.py +4 -1
  203. runbooks/{security_baseline → security}/checklist/cloudwatch_alarm_configuration.py +9 -2
  204. runbooks/{security_baseline → security}/checklist/guardduty_enabled.py +9 -2
  205. runbooks/{security_baseline → security}/checklist/multi_region_instance_usage.py +5 -1
  206. runbooks/{security_baseline → security}/checklist/root_access_key.py +6 -1
  207. runbooks/{security_baseline → security}/config-origin.json +1 -1
  208. runbooks/{security_baseline → security}/config.json +1 -1
  209. runbooks/{security_baseline → security}/permission.json +1 -1
  210. runbooks/{security_baseline → security}/report_generator.py +10 -2
  211. runbooks/{security_baseline → security}/report_template_en.html +7 -7
  212. runbooks/{security_baseline → security}/report_template_jp.html +7 -7
  213. runbooks/{security_baseline → security}/report_template_kr.html +12 -12
  214. runbooks/{security_baseline → security}/report_template_vn.html +7 -7
  215. runbooks/{security_baseline → security}/run_script.py +8 -2
  216. runbooks/{security_baseline → security}/security_baseline_tester.py +12 -4
  217. runbooks/{security_baseline → security}/utils/common.py +5 -1
  218. runbooks/utils/__init__.py +204 -0
  219. runbooks-0.7.0.dist-info/METADATA +375 -0
  220. runbooks-0.7.0.dist-info/RECORD +249 -0
  221. {runbooks-0.2.5.dist-info → runbooks-0.7.0.dist-info}/WHEEL +1 -1
  222. runbooks-0.7.0.dist-info/entry_points.txt +7 -0
  223. runbooks-0.7.0.dist-info/licenses/LICENSE +201 -0
  224. runbooks-0.7.0.dist-info/top_level.txt +3 -0
  225. runbooks/python101/calculator.py +0 -34
  226. runbooks/python101/config.py +0 -1
  227. runbooks/python101/exceptions.py +0 -16
  228. runbooks/python101/file_manager.py +0 -218
  229. runbooks/python101/toolkit.py +0 -153
  230. runbooks-0.2.5.dist-info/METADATA +0 -439
  231. runbooks-0.2.5.dist-info/RECORD +0 -61
  232. runbooks-0.2.5.dist-info/entry_points.txt +0 -3
  233. runbooks-0.2.5.dist-info/top_level.txt +0 -1
  234. /runbooks/{security_baseline/__init__.py → inventory/tests/script_test_data.py} +0 -0
  235. /runbooks/{security_baseline → security}/checklist/__init__.py +0 -0
  236. /runbooks/{security_baseline → security}/checklist/account_level_bucket_public_access.py +0 -0
  237. /runbooks/{security_baseline → security}/checklist/direct_attached_policy.py +0 -0
  238. /runbooks/{security_baseline → security}/checklist/iam_password_policy.py +0 -0
  239. /runbooks/{security_baseline → security}/checklist/iam_user_mfa.py +0 -0
  240. /runbooks/{security_baseline → security}/checklist/multi_region_trail.py +0 -0
  241. /runbooks/{security_baseline → security}/checklist/root_mfa.py +0 -0
  242. /runbooks/{security_baseline → security}/checklist/root_usage.py +0 -0
  243. /runbooks/{security_baseline → security}/checklist/trail_enabled.py +0 -0
  244. /runbooks/{security_baseline → security}/checklist/trusted_advisor.py +0 -0
  245. /runbooks/{security_baseline → security}/utils/__init__.py +0 -0
  246. /runbooks/{security_baseline → security}/utils/enums.py +0 -0
  247. /runbooks/{security_baseline → security}/utils/language.py +0 -0
  248. /runbooks/{security_baseline → security}/utils/level_const.py +0 -0
  249. /runbooks/{security_baseline → security}/utils/permission_list.py +0 -0
@@ -0,0 +1,719 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ AWS CloudFormation Orphaned Stack Detection and Analysis Script
5
+
6
+ This enterprise-grade script provides comprehensive detection and analysis of orphaned CloudFormation
7
+ stacks across multi-account AWS Organizations environments. Designed for infrastructure teams managing
8
+ CloudFormation StackSets at scale, offering automated orphaned stack identification, cross-account
9
+ stack reconciliation, and organizational governance support for infrastructure cleanup and compliance.
10
+
11
+ Key Features:
12
+ - Multi-account, multi-region CloudFormation stack and StackSet reconciliation
13
+ - Orphaned stack instance detection comparing StackSet definitions with deployed stacks
14
+ - Fragment-based filtering for targeted orphaned stack analysis
15
+ - Comprehensive cross-account stack inventory and comparison analysis
16
+ - Enterprise governance support with account exclusion and targeted analysis
17
+ - Multi-threaded processing for efficient large-scale stack discovery
18
+
19
+ Orphaned Stack Detection:
20
+ - Cross-references StackSet instances in management account with actual stacks in member accounts
21
+ - Identifies StackSet instances that exist in management account but not in target accounts
22
+ - Discovers stacks in member accounts that are not managed by any StackSet
23
+ - Provides detailed mismatch analysis for infrastructure cleanup and governance
24
+ - Supports fragment-based filtering for targeted orphaned stack identification
25
+
26
+ Authentication & Access:
27
+ - AWS Organizations support for centralized StackSet and stack management
28
+ - Cross-account role assumption for organizational stack visibility
29
+ - Regional validation and multi-region support for comprehensive coverage
30
+ - Profile-based authentication with comprehensive credential management
31
+
32
+ Performance & Scalability:
33
+ - Multi-threaded stack discovery for efficient large-scale processing
34
+ - Progress tracking and performance metrics for operational visibility
35
+ - Efficient credential management for multi-account stack enumeration
36
+ - Memory-efficient processing for extensive StackSet and stack inventories
37
+
38
+ Enterprise Use Cases:
39
+ - Infrastructure cleanup and orphaned resource identification
40
+ - StackSet governance and stack instance lifecycle management
41
+ - Organizational compliance monitoring and drift detection
42
+ - Infrastructure migration and consolidation planning
43
+ - Automated cleanup recommendation generation
44
+
45
+ Security & Compliance:
46
+ - Account exclusion capabilities preventing analysis on sensitive accounts
47
+ - Comprehensive audit logging for stack analysis and discovery operations
48
+ - Regional access validation and opt-in status verification
49
+ - Safe credential handling with automatic session management
50
+
51
+ Historical Context:
52
+ This script was originally created to support the "move_stack_instances.py" script by providing
53
+ recovery capabilities for stack instances that might be lost during StackSet migration operations.
54
+ While the move script now has built-in recovery, this script remains valuable for identifying
55
+ and analyzing orphaned stack instances that may occur during normal StackSet operations.
56
+
57
+ Dependencies:
58
+ - boto3: AWS SDK for CloudFormation and StackSet API access
59
+ - colorama: Terminal output formatting and colored display
60
+ - Custom modules: Inventory_Modules, ArgumentsClass, account_class for enterprise operations
61
+
62
+ Output Format:
63
+ - Comprehensive tabular analysis of orphaned stack instances
64
+ - Separate reporting for parent StackSet instances and child stacks
65
+ - Performance timing metrics and operational summaries
66
+ - Optional file export for further analysis and reporting
67
+ """
68
+
69
+ import logging
70
+ import sys
71
+ from os.path import split
72
+ from time import time
73
+
74
+ from account_class import aws_acct_access
75
+ from ArgumentsClass import CommonArguments
76
+
77
+ # import simplejson as json
78
+ from botocore.exceptions import ClientError
79
+ from colorama import Fore, init
80
+ from Inventory_Modules import (
81
+ display_results,
82
+ find_stack_instances3,
83
+ find_stacks2,
84
+ find_stacksets3,
85
+ get_credentials_for_accounts_in_org,
86
+ get_regions3,
87
+ print_timings,
88
+ )
89
+
90
+ init()
91
+ __version__ = "2024.05.18"
92
+ ERASE_LINE = "\x1b[2K"
93
+ begin_time = time()
94
+
95
+
96
+ ##################
97
+ # Functions
98
+ ##################
99
+
100
+
101
+ def parse_args(fargs):
102
+ """
103
+ Parse and validate command-line arguments for CloudFormation orphaned stack detection operations.
104
+
105
+ Configures comprehensive argument parsing for orphaned stack analysis across multi-account AWS
106
+ Organizations environments. Supports enterprise-grade CloudFormation management with profile
107
+ configuration, regional targeting, fragment-based filtering, and operational controls for
108
+ large-scale stack reconciliation and orphaned resource identification.
109
+
110
+ Args:
111
+ fargs (list): Command-line argument list for orphaned stack detection configuration
112
+
113
+ Returns:
114
+ argparse.Namespace: Parsed argument namespace containing:
115
+ - Profile: AWS profile for organizational CloudFormation access
116
+ - Region: Home region for StackSet management and control operations
117
+ - Fragments: Stack name fragments for targeted orphaned stack filtering
118
+ - Exact: Boolean flag for exact fragment matching vs substring matching
119
+ - Accounts: Specific account list for targeted orphaned stack analysis
120
+ - SkipAccounts: Account exclusion list for selective stack enumeration
121
+ - SkipProfiles: Profile exclusion list for selective discovery operations
122
+ - AccessRoles: Custom IAM roles for cross-account StackSet access
123
+ - Filename: Output file path for orphaned stack analysis results
124
+ - Time: Performance timing flag for operational metrics and optimization
125
+ - loglevel: Logging verbosity for operational visibility and troubleshooting
126
+ - SearchRegionList: Target regions for comprehensive stack instance analysis
127
+
128
+ CLI Argument Categories:
129
+ - Single profile support for centralized StackSet management and analysis
130
+ - Single home region for StackSet control plane operations
131
+ - Fragment-based filtering for targeted orphaned stack identification
132
+ - Extended arguments including account filtering and performance timing
133
+ - Role-based access controls for cross-account StackSet operations
134
+ - File export capabilities for analysis results and reporting
135
+ - Multi-region search support for comprehensive stack instance coverage
136
+
137
+ Enterprise Features:
138
+ - Organizational profile management for centralized StackSet governance
139
+ - Regional filtering for geo-distributed StackSet architectures
140
+ - Account inclusion/exclusion for selective orphaned stack analysis
141
+ - Performance monitoring with timing metrics for operational optimization
142
+ - Comprehensive logging controls for audit and compliance requirements
143
+ - Custom role support for enhanced security and access control
144
+
145
+ Orphaned Stack Detection Features:
146
+ - Home region specification for StackSet control plane access
147
+ - Multi-region search capabilities for comprehensive stack instance analysis
148
+ - Fragment-based filtering for targeted orphaned stack identification
149
+ - Account-specific analysis for focused cleanup and governance operations
150
+
151
+ Usage Examples:
152
+ - Basic analysis: --profile mgmt-profile --region us-east-1
153
+ - Fragment filtering: --fragment "MyApp" --exact for targeted analysis
154
+ - Multi-region search: --SearchRegions us-east-1 us-west-2 eu-west-1
155
+ - Account targeting: --accounts 123456789012 234567890123 for specific analysis
156
+ - Performance timing: --timing for operational metrics and optimization analysis
157
+ """
158
+ script_path, script_name = split(sys.argv[0]) # Extract script name for argument grouping
159
+
160
+ # Configure comprehensive argument parsing for orphaned stack detection
161
+ parser = CommonArguments()
162
+ parser.singleprofile() # Single AWS profile for centralized StackSet management
163
+ parser.singleregion() # Single home region for StackSet control operations
164
+ parser.fragment() # Fragment-based filtering for targeted stack identification
165
+ parser.extendedargs() # Extended arguments including account filtering and timing
166
+ parser.rolestouse() # Custom IAM roles for cross-account StackSet access
167
+ parser.save_to_file() # File export capabilities for analysis results
168
+ parser.verbosity() # Logging verbosity controls for operational visibility
169
+ parser.timing() # Performance timing metrics for operational optimization
170
+ parser.version(__version__)
171
+
172
+ # Script-specific arguments for orphaned stack detection operations
173
+ local = parser.my_parser.add_argument_group(script_name, "Parameters specific to this script")
174
+ local.add_argument(
175
+ "-R",
176
+ "--SearchRegions",
177
+ help="Target regions for comprehensive stack instance analysis and orphaned stack detection. "
178
+ "Supports multi-region search capabilities for thorough StackSet reconciliation across "
179
+ "geo-distributed AWS infrastructure deployments.",
180
+ default=["all"], # Default to all regions for comprehensive analysis
181
+ nargs="*", # Multiple regions supported for targeted analysis
182
+ metavar="region-name",
183
+ dest="SearchRegionList",
184
+ )
185
+
186
+ return parser.my_parser.parse_args(fargs)
187
+
188
+
189
+ def setup_auth_and_regions(fProfile: str, f_AccountList: list, f_Region: str, f_args) -> (aws_acct_access, list, list):
190
+ """
191
+ Initialize AWS authentication and configure regional scope for orphaned stack detection operations.
192
+
193
+ Establishes comprehensive AWS Organizations access and validates regional scope for CloudFormation
194
+ orphaned stack analysis across multi-account environments. Performs input validation, credential
195
+ initialization, account enumeration, and operational parameter display for enterprise-grade
196
+ StackSet governance and infrastructure cleanup operations.
197
+
198
+ Args:
199
+ fProfile (str): AWS profile name for organizational CloudFormation access
200
+ None uses default credentials or profile configuration
201
+ f_AccountList (list): Specific account list for targeted orphaned stack analysis
202
+ None includes all organizational accounts for comprehensive coverage
203
+ f_Region (str): Home region for StackSet control plane operations and management
204
+ Must be a single, valid AWS region for StackSet operations
205
+ f_args: Parsed command-line arguments containing:
206
+ - SearchRegionList: Target regions for stack instance search operations
207
+ - SkipAccounts: Account exclusion list for selective analysis
208
+ - Fragments: Stack name fragments for targeted filtering
209
+ - Exact: Boolean flag for exact fragment matching
210
+ - Accounts: Account inclusion list for focused analysis
211
+
212
+ Returns:
213
+ tuple: Three-element tuple containing:
214
+ - aws_acct_access: Initialized AWS account access object with organizational context
215
+ - AccountList: List of account IDs for orphaned stack analysis scope
216
+ - RegionList: List of regions for comprehensive stack instance search operations
217
+
218
+ Authentication & Validation:
219
+ - Profile validation ensuring single profile specification for centralized management
220
+ - AWS Organizations connectivity validation with comprehensive error handling
221
+ - Regional validation ensuring home region is available and properly configured
222
+ - Account list filtering supporting both inclusion and exclusion patterns
223
+
224
+ Organizational Context:
225
+ - Account enumeration across AWS Organizations for comprehensive analysis scope
226
+ - Management account identification and organizational hierarchy establishment
227
+ - Child account filtering based on account inclusion/exclusion specifications
228
+ - Account status validation ensuring active accounts for analysis operations
229
+
230
+ Operational Display:
231
+ - Comprehensive parameter summary for operational visibility and confirmation
232
+ - Fragment filtering specifications with exact vs substring matching display
233
+ - Account scope display showing targeted vs comprehensive analysis mode
234
+ - Regional scope display for multi-region stack instance search operations
235
+
236
+ Error Handling:
237
+ - Profile validation with informative error messages and graceful exit
238
+ - AWS connectivity error handling with detailed diagnostic information
239
+ - Regional validation preventing invalid region specifications
240
+ - Comprehensive input validation with clear error messaging
241
+
242
+ Enterprise Features:
243
+ - AWS Organizations support for centralized StackSet governance
244
+ - Account filtering capabilities for selective orphaned stack analysis
245
+ - Multi-region support for comprehensive stack instance coverage
246
+ - Operational parameter display for audit trails and confirmation
247
+ """
248
+ # Perform comprehensive input validation for profile specification
249
+ if isinstance(fProfile, str) or fProfile is None:
250
+ pass # Valid profile specification (string or None for default)
251
+ else: # Invalid profile type (list, integer, etc.) - should be caught at argparse level
252
+ print(
253
+ f"{Fore.RED}You specified an invalid profile name. This script only allows for one profile at a time. Please try again.{Fore.RESET}"
254
+ )
255
+ sys.exit(7)
256
+
257
+ # Initialize AWS account access with comprehensive error handling
258
+ try:
259
+ aws_acct = aws_acct_access(fProfile)
260
+ except ConnectionError as my_Error:
261
+ logging.error(f"Exiting due to error: {my_Error}")
262
+ sys.exit(8)
263
+
264
+ # Configure regional scope for orphaned stack detection operations
265
+ AllRegions = get_regions3(aws_acct) # All available regions for validation
266
+ RegionList = get_regions3(aws_acct, f_args.SearchRegionList) # Target regions for stack instance search
267
+
268
+ # Validate home region specification ensuring single region for StackSet control plane
269
+ if f_Region.lower() not in AllRegions:
270
+ print(
271
+ f"{Fore.RED}You specified '{f_Region}' as the region, but this script only works with a single region.\n"
272
+ f"Please run the command again and specify only a single, valid region{Fore.RESET}"
273
+ )
274
+ sys.exit(9)
275
+
276
+ print()
277
+
278
+ # Configure account scope for orphaned stack analysis with organizational context
279
+ ChildAccounts = [] # List of account dictionaries: AccountId, AccountEmail, AccountStatus, MgmtAccount
280
+
281
+ if f_AccountList is None:
282
+ # Include all organizational accounts for comprehensive orphaned stack analysis
283
+ ChildAccounts = aws_acct.ChildAccounts
284
+ else:
285
+ # Filter accounts based on user-specified inclusion list for targeted analysis
286
+ for account in aws_acct.ChildAccounts:
287
+ if account["AccountId"] in f_AccountList:
288
+ ChildAccounts.append(
289
+ {
290
+ "AccountId": account["AccountId"], # Account identifier for stack analysis
291
+ "AccountEmail": account["AccountEmail"], # Account contact for audit context
292
+ "AccountStatus": account["AccountStatus"], # Account operational status
293
+ "MgmtAccount": account["MgmtAccount"], # Management account reference
294
+ }
295
+ )
296
+
297
+ # Extract account IDs for efficient processing and operational context
298
+ AccountList = [account["AccountId"] for account in ChildAccounts]
299
+
300
+ # Display comprehensive operational parameters for confirmation and audit trails
301
+ print(f"You asked me to find orphaned stacksets that match the following:")
302
+ print(f"\t\tIn the {aws_acct.AccountType} account {aws_acct.acct_number}")
303
+ print(f"\t\tIn this home Region: {f_Region}")
304
+
305
+ # Display search region configuration if specified
306
+ print(
307
+ f"\t\tFor stackset instances whose region matches this region fragment: {f_args.SearchRegionList}"
308
+ ) if f_args.SearchRegionList is not None else ""
309
+
310
+ # Display account exclusion list if specified
311
+ print(
312
+ f"While skipping these accounts:\n{Fore.RED}{f_args.SkipAccounts}{Fore.RESET}"
313
+ ) if f_args.SkipAccounts is not None else ""
314
+
315
+ # Display fragment filtering configuration with exact vs substring matching
316
+ if f_args.Exact:
317
+ print(f"\t\tFor stacksets that {Fore.RED}exactly match{Fore.RESET}: {f_args.Fragments}")
318
+ else:
319
+ print(
320
+ f"\t\tFor stacksets that contain th{'is fragment' if len(f_args.Fragments) == 1 else 'ese fragments'}: {f_args.Fragments}"
321
+ )
322
+
323
+ # Display account scope configuration for targeted vs comprehensive analysis
324
+ if f_args.Accounts is None:
325
+ print(f"\t\tFor stack instances across all accounts")
326
+ else:
327
+ print(
328
+ f"\t\tSpecifically to find th{'ese' if len(f_args.Accounts) > 1 else 'is'} account number{'s' if len(f_args.Accounts) > 1 else ''}: {f_args.Accounts}"
329
+ )
330
+ print()
331
+
332
+ return aws_acct, AccountList, RegionList
333
+
334
+
335
+ def find_stacks_within_child_accounts(fall_credentials, fFragmentlist: list = None, threads: int = 25):
336
+ """
337
+ Discover and enumerate CloudFormation stacks across multiple organizational accounts using multi-threading.
338
+
339
+ Performs comprehensive CloudFormation stack discovery using multi-threaded processing to efficiently
340
+ inventory stacks across large-scale AWS Organizations environments. Designed for orphaned stack
341
+ detection by providing detailed stack metadata extraction from member accounts for reconciliation
342
+ with StackSet instances in the management account.
343
+
344
+ Args:
345
+ fall_credentials (list): List of credential dictionaries for cross-account stack discovery containing:
346
+ - AccountId: AWS account number for CloudFormation stack access
347
+ - Region: Target AWS region for stack enumeration
348
+ - Success: Boolean indicating credential validity and access status
349
+ - AccountNumber: Alternative account identifier format
350
+ fFragmentlist (list): Stack name fragments for targeted search and filtering
351
+ None defaults to ["all"] for comprehensive stack discovery
352
+ threads (int): Maximum number of worker threads for concurrent processing
353
+ Default 25, automatically limited by credential count for optimization
354
+
355
+ Returns:
356
+ list: Comprehensive list of stack dictionaries containing:
357
+ - StackName: CloudFormation stack name identifier
358
+ - StackId: Unique AWS CloudFormation stack identifier
359
+ - StackStatus: Current operational status
360
+ - AccountId: AWS account containing the stack
361
+ - Region: AWS region where stack is deployed
362
+ - Additional stack metadata for orphaned stack analysis
363
+
364
+ Multi-threaded Architecture:
365
+ - Queue-based worker pattern for concurrent stack discovery
366
+ - Configurable worker thread pool with automatic scaling
367
+ - Thread-safe stack aggregation for comprehensive result collection
368
+ - Graceful error handling for authorization and access issues
369
+
370
+ Stack Discovery Features:
371
+ - Multi-account, multi-region CloudFormation stack enumeration
372
+ - Fragment-based filtering for targeted stack identification
373
+ - Comprehensive stack metadata extraction for governance analysis
374
+ - Cross-account stack visibility for organizational inventory
375
+ - Regional stack distribution analysis for operational planning
376
+
377
+ Performance Optimization:
378
+ - Concurrent processing for efficient large-scale stack discovery
379
+ - Worker thread scaling based on credential count for optimal performance
380
+ - Queue management for efficient work distribution and completion tracking
381
+ - Memory-efficient processing for extensive stack inventories
382
+
383
+ Enterprise Infrastructure Governance:
384
+ - Organizational stack visibility across accounts and regions
385
+ - Stack metadata aggregation for compliance and audit tracking
386
+ - Fragment-based search capabilities for targeted stack management
387
+ - Comprehensive error handling for operational resilience and troubleshooting
388
+
389
+ Error Handling:
390
+ - Authorization failure detection with graceful degradation
391
+ - AWS API error management with comprehensive logging
392
+ - Credential validation and failure tracking for multi-account operations
393
+ - Regional access validation preventing unauthorized stack enumeration
394
+ """
395
+ from queue import Queue
396
+ from threading import Thread
397
+
398
+ class FindStacks(Thread):
399
+ """
400
+ Multi-threaded worker class for concurrent CloudFormation stack discovery.
401
+
402
+ Implements thread-safe stack discovery using queue-based work distribution for
403
+ efficient processing of CloudFormation stacks across organizational accounts
404
+ and regions.
405
+ """
406
+
407
+ def __init__(self, fqueue: Queue):
408
+ Thread.__init__(self)
409
+ self.queue = fqueue
410
+
411
+ def run(self):
412
+ while True:
413
+ # Extract work item from queue with account credentials and processing context
414
+ c_credential, c_fragmentlist = self.queue.get()
415
+
416
+ # Discover CloudFormation stacks with comprehensive error handling
417
+ try:
418
+ if c_credential["Success"]:
419
+ # Execute stack discovery using validated credentials
420
+ account_and_region_stacks = find_stacks2(c_credential, c_credential["Region"], c_fragmentlist)
421
+ AllFoundStacks.extend(account_and_region_stacks)
422
+ else:
423
+ # Skip failed credentials with informative logging
424
+ logging.info(
425
+ f"Skipping {c_credential['AccountNumber']} in {c_credential['Region']} as we failed to successfully access"
426
+ )
427
+ except Exception as my_Error:
428
+ # Handle comprehensive stack discovery errors with detailed logging
429
+ logging.error(
430
+ f"Error accessing account {c_credential['AccountId']} in region {c_credential['Region']} "
431
+ f"Skipping this account"
432
+ )
433
+ logging.info(f"Actual Error: {my_Error}")
434
+ finally:
435
+ # Mark queue item as completed for work distribution tracking
436
+ self.queue.task_done()
437
+
438
+ # Initialize multi-threaded processing infrastructure for stack discovery
439
+ checkqueue = Queue() # Queue for work distribution across worker threads
440
+
441
+ # Configure fragment filtering with default comprehensive discovery
442
+ if fFragmentlist is None:
443
+ fFragmentlist = ["all"] # Default to all stacks for comprehensive analysis
444
+
445
+ # Note: Account and skip account filtering is handled by upstream credential management
446
+ # This function receives pre-filtered credentials based on user specifications
447
+
448
+ # Configure optimal worker thread count based on credential count and system limits
449
+ WorkerThreads = min(len(fall_credentials), threads)
450
+
451
+ # Initialize aggregated results collection for discovered stacks
452
+ AllFoundStacks = []
453
+
454
+ # Create and start worker thread pool for concurrent stack discovery
455
+ for x in range(WorkerThreads):
456
+ worker = FindStacks(checkqueue)
457
+ # Daemon threads allow main thread exit even if workers are still processing
458
+ worker.daemon = True
459
+ worker.start()
460
+
461
+ # Queue stack discovery work items for worker thread processing
462
+ for credential in fall_credentials:
463
+ logging.info(f"Queueing account {credential['AccountId']} and {credential['Region']}")
464
+ try:
465
+ # Queue account and region combination for worker thread processing
466
+ # Note: Tuple structure is critical for proper parameter expansion in worker threads
467
+ checkqueue.put((credential, fFragmentlist))
468
+ except ClientError as my_Error:
469
+ # Handle authorization failures with informative error messaging
470
+ if "AuthFailure" in str(my_Error):
471
+ logging.error(
472
+ f"Authorization Failure accessing account {credential['AccountId']} in {credential['Region']}"
473
+ )
474
+ logging.warning(f"It's possible that the region {credential['Region']} hasn't been opted-into")
475
+ pass
476
+
477
+ # Wait for all worker threads to complete stack discovery processing
478
+ checkqueue.join()
479
+ return AllFoundStacks
480
+
481
+
482
+ def reconcile_between_parent_stacksets_and_children_stacks(f_parent_stack_instances: list, f_child_stacks: list):
483
+ """
484
+ Perform comprehensive reconciliation analysis between StackSet instances and deployed stacks.
485
+
486
+ Executes detailed cross-referencing between CloudFormation StackSet instances managed in the
487
+ management account and actual CloudFormation stacks deployed in member accounts to identify
488
+ orphaned resources, missing deployments, and infrastructure governance issues requiring cleanup
489
+ or remediation across organizational AWS environments.
490
+
491
+ Args:
492
+ f_parent_stack_instances (list): List of StackSet instance dictionaries from management account containing:
493
+ - StackId: Unique CloudFormation stack identifier for matching
494
+ - Account: Target account for StackSet instance deployment
495
+ - Region: Target region for StackSet instance deployment
496
+ - StackSetId: Parent StackSet identifier for organizational context
497
+ - Status: Current StackSet instance operational status
498
+ - StatusReason: Detailed status reason for troubleshooting
499
+ f_child_stacks (list): List of actual stack dictionaries from member accounts containing:
500
+ - StackId: Unique CloudFormation stack identifier for matching
501
+ - StackName: CloudFormation stack name (StackSet- prefix indicates StackSet managed)
502
+ - AccountNumber: Account containing the deployed stack
503
+ - Region: Region where stack is deployed
504
+ - StackStatus: Current stack operational status
505
+
506
+ Processing Logic:
507
+ 1. Cross-reference StackSet instances with deployed stacks using StackId matching
508
+ 2. Mark matched instances to identify properly managed StackSet deployments
509
+ 3. Identify parent StackSet instances without corresponding child stacks (missing deployments)
510
+ 4. Identify child stacks without corresponding parent StackSet instances (orphaned stacks)
511
+ 5. Filter child stacks to include only StackSet-managed stacks (StackSet- prefix)
512
+ 6. Generate comprehensive reports for infrastructure cleanup and governance
513
+
514
+ Orphaned Stack Detection:
515
+ - Parent instances not in child stacks indicate failed or missing StackSet deployments
516
+ - Child stacks not in parent instances indicate orphaned StackSet-managed resources
517
+ - Cross-account stack reconciliation ensuring organizational infrastructure alignment
518
+ - Performance timing for large-scale reconciliation operations
519
+
520
+ Reporting & Display:
521
+ - Separate tabular reports for parent and child orphaned resources
522
+ - Sortable display with account, region, and resource identifiers
523
+ - Optional file export for further analysis and remediation planning
524
+ - Comprehensive operational metrics and reconciliation statistics
525
+
526
+ Enterprise Governance:
527
+ - Infrastructure cleanup recommendations based on orphaned resource identification
528
+ - StackSet lifecycle management insights for operational optimization
529
+ - Organizational compliance monitoring through resource reconciliation
530
+ - Automated remediation planning through detailed orphaned resource analysis
531
+
532
+ Performance Monitoring:
533
+ - Comparison metrics tracking reconciliation operation efficiency
534
+ - Timing analysis for large-scale infrastructure reconciliation operations
535
+ - Memory-efficient processing for extensive StackSet and stack inventories
536
+ - Operational visibility through detailed progress and result logging
537
+ """
538
+ # Initialize reconciliation tracking metrics for operational monitoring
539
+ child_comparisons = 0 # Counter for child stack comparison operations
540
+ parent_comparisons = 0 # Counter for parent StackSet instance comparisons
541
+ i = 0 # Match counter for successful reconciliation tracking
542
+
543
+ # Execute comprehensive cross-referencing between parent StackSet instances and child stacks
544
+ for ParentInstance in f_parent_stack_instances:
545
+ parent_comparisons += 1 # Track parent instance processing for metrics
546
+
547
+ # Compare current parent instance against all child stacks for matching
548
+ for Childinstance in f_child_stacks:
549
+ child_comparisons += 1 # Track child stack comparison operations
550
+
551
+ # Perform StackId-based matching to identify properly managed StackSet deployments
552
+ if "StackId" in ParentInstance.keys() and Childinstance["StackId"] == ParentInstance["StackId"]:
553
+ i += 1 # Increment successful match counter
554
+
555
+ # Log successful matches with timing for performance analysis
556
+ logging.debug(f"**** Match {i}!! **** - {time() - begin_time:.6f}")
557
+ logging.debug(f"Childinstance: {Childinstance['StackId']}")
558
+ logging.debug(f"ParentInstance: {ParentInstance['StackId']}")
559
+
560
+ # Mark both instances as matched for filtering operations
561
+ Childinstance["Matches"] = ParentInstance["StackId"] # Child stack matches parent
562
+ ParentInstance["Matches"] = Childinstance["StackId"] # Parent instance matches child
563
+ else:
564
+ continue # No match found, proceed to next comparison
565
+
566
+ # Display reconciliation performance metrics for operational visibility
567
+ print_timings(
568
+ pTiming,
569
+ verbose,
570
+ begin_time,
571
+ f"We compared {len(AllChildStackInstances)} child stacks against {len(AllParentStackInstancesInStackSets)} parent stack instances",
572
+ )
573
+
574
+ # Identify StackSet instances in management account without corresponding deployed stacks
575
+ Parent_Instances_Not_In_Children_Stacks = [
576
+ x for x in AllParentStackInstancesInStackSets if "Matches" not in x.keys()
577
+ ]
578
+
579
+ # Identify StackSet-managed stacks in member accounts without corresponding parent instances
580
+ # Filter for StackSet-managed stacks only (StackSet- prefix) to exclude regular account stacks
581
+ Child_Instances_Not_In_Parent_Stacks = [
582
+ x for x in AllChildStackInstances if "Matches" not in x.keys() and (x["StackName"].find("StackSet-") > -1)
583
+ ]
584
+
585
+ # Display comprehensive reconciliation results for operational analysis
586
+ print()
587
+ print(
588
+ f"We found {len(Parent_Instances_Not_In_Children_Stacks)} parent stack instances that are not in the child stacks"
589
+ )
590
+ print(f"We found {len(Child_Instances_Not_In_Parent_Stacks)} child stacks that are not in the parent stacksets")
591
+ print()
592
+
593
+ # Generate detailed tabular reports for orphaned resource analysis (if verbose logging enabled)
594
+ if verbose < 50:
595
+ # Configure display formatting for parent StackSet instances without child stacks
596
+ parent_display_dict = {
597
+ "Account": {"DisplayOrder": 1, "Heading": "Acct Number"}, # Target account for deployment
598
+ "Region": {"DisplayOrder": 2, "Heading": "Region"}, # Target region for deployment
599
+ "StackSetId": {"DisplayOrder": 3, "Heading": "StackSet Id"}, # Parent StackSet identifier
600
+ "Status": {"DisplayOrder": 4, "Heading": "Status"}, # StackSet instance status
601
+ "StatusReason": {"DisplayOrder": 5, "Heading": "Possible Reason"}, # Detailed status reason
602
+ }
603
+
604
+ # Display and export parent instances without corresponding child stacks
605
+ print(f"Stack Instances in the Root Account that don't appear in the Children")
606
+ sorted_Parent_Instances_Not_In_Children_Stacks = sorted(
607
+ Parent_Instances_Not_In_Children_Stacks, key=lambda k: (k["Account"], k["Region"], k["StackSetId"])
608
+ )
609
+ display_results(
610
+ sorted_Parent_Instances_Not_In_Children_Stacks, parent_display_dict, None, f"{pFilename}-Parent"
611
+ )
612
+
613
+ # Configure display formatting for child stacks without parent StackSet instances
614
+ child_display_dict = {
615
+ "AccountNumber": {"DisplayOrder": 1, "Heading": "Acct Number"}, # Account containing orphaned stack
616
+ "Region": {"DisplayOrder": 2, "Heading": "Region"}, # Region containing orphaned stack
617
+ "StackName": {"DisplayOrder": 3, "Heading": "Stack Name"}, # Orphaned stack name
618
+ "StackStatus": {"DisplayOrder": 4, "Heading": "Status"}, # Current stack status
619
+ }
620
+
621
+ # Display and export child stacks without corresponding parent StackSet instances
622
+ print(f"Stacks in the Children accounts that don't appear in the Root Stacksets")
623
+ sorted_Child_Instances_Not_In_Parent_Stacks = sorted(
624
+ Child_Instances_Not_In_Parent_Stacks, key=lambda k: (k["AccountNumber"], k["Region"], k["StackName"])
625
+ )
626
+ display_results(sorted_Child_Instances_Not_In_Parent_Stacks, child_display_dict, None, f"{pFilename}-Child")
627
+
628
+
629
+ ##################
630
+ # Main
631
+ ##################
632
+
633
+ if __name__ == "__main__":
634
+ args = parse_args(sys.argv[1:])
635
+ pProfile = args.Profile
636
+ pRegion = args.Region
637
+ pSearchRegionList = args.SearchRegionList
638
+ pAccounts = args.Accounts
639
+ pSkipAccounts = args.SkipAccounts
640
+ pSkipProfiles = args.SkipProfiles
641
+ pFilename = args.Filename
642
+ pRootOnly = False # It doesn't make any sense to think that this script would be used for only the root account
643
+ pExact = args.Exact
644
+ pRoles = args.AccessRoles
645
+ verbose = args.loglevel
646
+ pTiming = args.Time
647
+ pFragments = args.Fragments
648
+ # Setup logging levels
649
+ logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s")
650
+ logging.getLogger("boto3").setLevel(logging.CRITICAL)
651
+ logging.getLogger("botocore").setLevel(logging.CRITICAL)
652
+ logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
653
+ logging.getLogger("urllib3").setLevel(logging.CRITICAL)
654
+
655
+ ERASE_LINE = "\x1b[2K"
656
+ begin_time = time()
657
+
658
+ # Setup credentials and regions (filtered by what they wanted to check)
659
+ aws_acct, AccountList, RegionList = setup_auth_and_regions(pProfile, pAccounts, pRegion, args)
660
+ # Determine the accounts we're checking
661
+ print_timings(pTiming, verbose, begin_time, "Just setup account and region list")
662
+ AllCredentials = get_credentials_for_accounts_in_org(
663
+ aws_acct, pSkipAccounts, pRootOnly, AccountList, pProfile, RegionList, pRoles, pTiming
664
+ )
665
+ print_timings(
666
+ pTiming,
667
+ verbose,
668
+ begin_time,
669
+ f"Finished getting {len(AllCredentials)} credentials for all accounts and regions in spec...",
670
+ )
671
+
672
+ # Connect to every account, and in every region specified, to find all stacks
673
+ print(
674
+ f"Now finding all stacks across {'all' if pAccounts is None else (len(pAccounts) * len(RegionList))} accounts and regions under the {aws_acct.AccountType} account {aws_acct.acct_number}"
675
+ )
676
+ AllChildStackInstances = find_stacks_within_child_accounts(AllCredentials, pFragments)
677
+ print_timings(
678
+ pTiming, verbose, begin_time, f"Just finished getting {len(AllChildStackInstances)} children stack instances"
679
+ )
680
+ # and then compare them with the stackset instances managed within the Root account, and find anything that doesn't match
681
+
682
+ # This is the list of stacksets in the root account
683
+ AllParentStackSets = find_stacksets3(aws_acct, pRegion, pFragments, pExact)
684
+ print_timings(
685
+ pTiming, verbose, begin_time, f"Just finished getting {len(AllParentStackSets['StackSets'])} parent stack sets"
686
+ )
687
+ print(f"Now getting all the stack instances for all {len(AllParentStackSets)} stacksets")
688
+ # This will be the listing of the stack_instances in each of the stacksets in the root account
689
+ AllParentStackInstancesInStackSets = []
690
+ for stackset_name, stackset_attributes in AllParentStackSets["StackSets"].items():
691
+ StackInstancesInStackSets = find_stack_instances3(
692
+ aws_acct, pRegion, stackset_name, faccountlist=AccountList, fregionlist=RegionList
693
+ )
694
+ # TODO: Filter out skipped / closed accounts within the stacksets
695
+ AllParentStackInstancesInStackSets.extend(StackInstancesInStackSets)
696
+ print_timings(
697
+ pTiming,
698
+ verbose,
699
+ begin_time,
700
+ f"Just finished getting {len(AllParentStackInstancesInStackSets)} parent stack instances",
701
+ )
702
+ # Then compare the stack_instances in the root account with the stack_instances in the child accounts to see if anything is missing
703
+ print(f"We found {len(AllChildStackInstances)} stack instances in the {len(AccountList)} child accounts")
704
+ print(
705
+ f"We found {len(AllParentStackInstancesInStackSets)} stack instances in the {len(AllParentStackSets['StackSets'])} stacksets in the root account"
706
+ )
707
+ print(f"Now cross-referencing these to find if there are any orphaned stacks...")
708
+ # Find the stacks that are in the root account but not in the child accounts
709
+ # And find any stack instances in the children accounts that are not in the root account
710
+ # And display them to the screen...
711
+ reconcile_between_parent_stacksets_and_children_stacks(AllParentStackInstancesInStackSets, AllChildStackInstances)
712
+
713
+ if pTiming:
714
+ print(ERASE_LINE)
715
+ print(f"{Fore.GREEN}This script took {time() - begin_time:.2f} seconds{Fore.RESET}")
716
+
717
+ print()
718
+ print("Thanks for using this script...")
719
+ print()