runbooks 0.2.5__py3-none-any.whl → 0.6.1__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 (221) hide show
  1. conftest.py +26 -0
  2. jupyter-agent/.env.template +2 -0
  3. jupyter-agent/.gitattributes +35 -0
  4. jupyter-agent/README.md +16 -0
  5. jupyter-agent/app.py +256 -0
  6. jupyter-agent/cloudops-agent.png +0 -0
  7. jupyter-agent/ds-system-prompt.txt +154 -0
  8. jupyter-agent/jupyter-agent.png +0 -0
  9. jupyter-agent/llama3_template.jinja +123 -0
  10. jupyter-agent/requirements.txt +9 -0
  11. jupyter-agent/utils.py +409 -0
  12. runbooks/__init__.py +71 -3
  13. runbooks/__main__.py +13 -0
  14. runbooks/aws/ec2_describe_instances.py +1 -1
  15. runbooks/aws/ec2_run_instances.py +8 -2
  16. runbooks/aws/ec2_start_stop_instances.py +17 -4
  17. runbooks/aws/ec2_unused_volumes.py +5 -1
  18. runbooks/aws/s3_create_bucket.py +4 -2
  19. runbooks/aws/s3_list_objects.py +6 -1
  20. runbooks/aws/tagging_lambda_handler.py +13 -2
  21. runbooks/aws/tags.json +12 -0
  22. runbooks/base.py +353 -0
  23. runbooks/cfat/README.md +49 -0
  24. runbooks/cfat/__init__.py +74 -0
  25. runbooks/cfat/app.ts +644 -0
  26. runbooks/cfat/assessment/__init__.py +40 -0
  27. runbooks/cfat/assessment/asana-import.csv +39 -0
  28. runbooks/cfat/assessment/cfat-checks.csv +31 -0
  29. runbooks/cfat/assessment/cfat.txt +520 -0
  30. runbooks/cfat/assessment/collectors.py +200 -0
  31. runbooks/cfat/assessment/jira-import.csv +39 -0
  32. runbooks/cfat/assessment/runner.py +387 -0
  33. runbooks/cfat/assessment/validators.py +290 -0
  34. runbooks/cfat/cli.py +103 -0
  35. runbooks/cfat/docs/asana-import.csv +24 -0
  36. runbooks/cfat/docs/cfat-checks.csv +31 -0
  37. runbooks/cfat/docs/cfat.txt +335 -0
  38. runbooks/cfat/docs/checks-output.png +0 -0
  39. runbooks/cfat/docs/cloudshell-console-run.png +0 -0
  40. runbooks/cfat/docs/cloudshell-download.png +0 -0
  41. runbooks/cfat/docs/cloudshell-output.png +0 -0
  42. runbooks/cfat/docs/downloadfile.png +0 -0
  43. runbooks/cfat/docs/jira-import.csv +24 -0
  44. runbooks/cfat/docs/open-cloudshell.png +0 -0
  45. runbooks/cfat/docs/report-header.png +0 -0
  46. runbooks/cfat/models.py +1026 -0
  47. runbooks/cfat/package-lock.json +5116 -0
  48. runbooks/cfat/package.json +38 -0
  49. runbooks/cfat/report.py +496 -0
  50. runbooks/cfat/reporting/__init__.py +46 -0
  51. runbooks/cfat/reporting/exporters.py +337 -0
  52. runbooks/cfat/reporting/formatters.py +496 -0
  53. runbooks/cfat/reporting/templates.py +135 -0
  54. runbooks/cfat/run-assessment.sh +23 -0
  55. runbooks/cfat/runner.py +69 -0
  56. runbooks/cfat/src/actions/check-cloudtrail-existence.ts +43 -0
  57. runbooks/cfat/src/actions/check-config-existence.ts +37 -0
  58. runbooks/cfat/src/actions/check-control-tower.ts +37 -0
  59. runbooks/cfat/src/actions/check-ec2-existence.ts +46 -0
  60. runbooks/cfat/src/actions/check-iam-users.ts +50 -0
  61. runbooks/cfat/src/actions/check-legacy-cur.ts +30 -0
  62. runbooks/cfat/src/actions/check-org-cloudformation.ts +30 -0
  63. runbooks/cfat/src/actions/check-vpc-existence.ts +43 -0
  64. runbooks/cfat/src/actions/create-asanaimport.ts +14 -0
  65. runbooks/cfat/src/actions/create-backlog.ts +372 -0
  66. runbooks/cfat/src/actions/create-jiraimport.ts +15 -0
  67. runbooks/cfat/src/actions/create-report.ts +616 -0
  68. runbooks/cfat/src/actions/define-account-type.ts +51 -0
  69. runbooks/cfat/src/actions/get-enabled-org-policy-types.ts +40 -0
  70. runbooks/cfat/src/actions/get-enabled-org-services.ts +26 -0
  71. runbooks/cfat/src/actions/get-idc-info.ts +34 -0
  72. runbooks/cfat/src/actions/get-org-da-accounts.ts +34 -0
  73. runbooks/cfat/src/actions/get-org-details.ts +35 -0
  74. runbooks/cfat/src/actions/get-org-member-accounts.ts +44 -0
  75. runbooks/cfat/src/actions/get-org-ous.ts +35 -0
  76. runbooks/cfat/src/actions/get-regions.ts +22 -0
  77. runbooks/cfat/src/actions/zip-assessment.ts +27 -0
  78. runbooks/cfat/src/types/index.d.ts +147 -0
  79. runbooks/cfat/tests/__init__.py +141 -0
  80. runbooks/cfat/tests/test_cli.py +340 -0
  81. runbooks/cfat/tests/test_integration.py +290 -0
  82. runbooks/cfat/tests/test_models.py +505 -0
  83. runbooks/cfat/tests/test_reporting.py +354 -0
  84. runbooks/cfat/tsconfig.json +16 -0
  85. runbooks/cfat/webpack.config.cjs +27 -0
  86. runbooks/config.py +260 -0
  87. runbooks/finops/__init__.py +88 -0
  88. runbooks/finops/aws_client.py +245 -0
  89. runbooks/finops/cli.py +151 -0
  90. runbooks/finops/cost_processor.py +410 -0
  91. runbooks/finops/dashboard_runner.py +448 -0
  92. runbooks/finops/helpers.py +355 -0
  93. runbooks/finops/main.py +14 -0
  94. runbooks/finops/profile_processor.py +174 -0
  95. runbooks/finops/types.py +66 -0
  96. runbooks/finops/visualisations.py +80 -0
  97. runbooks/inventory/.gitignore +354 -0
  98. runbooks/inventory/ArgumentsClass.py +261 -0
  99. runbooks/inventory/Inventory_Modules.py +6130 -0
  100. runbooks/inventory/LandingZone/delete_lz.py +1075 -0
  101. runbooks/inventory/README.md +1320 -0
  102. runbooks/inventory/__init__.py +62 -0
  103. runbooks/inventory/account_class.py +532 -0
  104. runbooks/inventory/all_my_instances_wrapper.py +123 -0
  105. runbooks/inventory/aws_decorators.py +201 -0
  106. runbooks/inventory/cfn_move_stack_instances.py +1526 -0
  107. runbooks/inventory/check_cloudtrail_compliance.py +614 -0
  108. runbooks/inventory/check_controltower_readiness.py +1107 -0
  109. runbooks/inventory/check_landingzone_readiness.py +711 -0
  110. runbooks/inventory/cloudtrail.md +727 -0
  111. runbooks/inventory/collectors/__init__.py +20 -0
  112. runbooks/inventory/collectors/aws_compute.py +518 -0
  113. runbooks/inventory/collectors/aws_networking.py +275 -0
  114. runbooks/inventory/collectors/base.py +222 -0
  115. runbooks/inventory/core/__init__.py +19 -0
  116. runbooks/inventory/core/collector.py +303 -0
  117. runbooks/inventory/core/formatter.py +296 -0
  118. runbooks/inventory/delete_s3_buckets_objects.py +169 -0
  119. runbooks/inventory/discovery.md +81 -0
  120. runbooks/inventory/draw_org_structure.py +748 -0
  121. runbooks/inventory/ec2_vpc_utils.py +341 -0
  122. runbooks/inventory/find_cfn_drift_detection.py +272 -0
  123. runbooks/inventory/find_cfn_orphaned_stacks.py +719 -0
  124. runbooks/inventory/find_cfn_stackset_drift.py +733 -0
  125. runbooks/inventory/find_ec2_security_groups.py +669 -0
  126. runbooks/inventory/find_landingzone_versions.py +201 -0
  127. runbooks/inventory/find_vpc_flow_logs.py +1221 -0
  128. runbooks/inventory/inventory.sh +659 -0
  129. runbooks/inventory/list_cfn_stacks.py +558 -0
  130. runbooks/inventory/list_cfn_stackset_operation_results.py +252 -0
  131. runbooks/inventory/list_cfn_stackset_operations.py +734 -0
  132. runbooks/inventory/list_cfn_stacksets.py +453 -0
  133. runbooks/inventory/list_config_recorders_delivery_channels.py +681 -0
  134. runbooks/inventory/list_ds_directories.py +354 -0
  135. runbooks/inventory/list_ec2_availability_zones.py +286 -0
  136. runbooks/inventory/list_ec2_ebs_volumes.py +244 -0
  137. runbooks/inventory/list_ec2_instances.py +425 -0
  138. runbooks/inventory/list_ecs_clusters_and_tasks.py +562 -0
  139. runbooks/inventory/list_elbs_load_balancers.py +411 -0
  140. runbooks/inventory/list_enis_network_interfaces.py +526 -0
  141. runbooks/inventory/list_guardduty_detectors.py +568 -0
  142. runbooks/inventory/list_iam_policies.py +404 -0
  143. runbooks/inventory/list_iam_roles.py +518 -0
  144. runbooks/inventory/list_iam_saml_providers.py +359 -0
  145. runbooks/inventory/list_lambda_functions.py +882 -0
  146. runbooks/inventory/list_org_accounts.py +446 -0
  147. runbooks/inventory/list_org_accounts_users.py +354 -0
  148. runbooks/inventory/list_rds_db_instances.py +406 -0
  149. runbooks/inventory/list_route53_hosted_zones.py +318 -0
  150. runbooks/inventory/list_servicecatalog_provisioned_products.py +575 -0
  151. runbooks/inventory/list_sns_topics.py +360 -0
  152. runbooks/inventory/list_ssm_parameters.py +402 -0
  153. runbooks/inventory/list_vpc_subnets.py +433 -0
  154. runbooks/inventory/list_vpcs.py +422 -0
  155. runbooks/inventory/lockdown_cfn_stackset_role.py +224 -0
  156. runbooks/inventory/models/__init__.py +24 -0
  157. runbooks/inventory/models/account.py +192 -0
  158. runbooks/inventory/models/inventory.py +309 -0
  159. runbooks/inventory/models/resource.py +247 -0
  160. runbooks/inventory/recover_cfn_stack_ids.py +205 -0
  161. runbooks/inventory/requirements.txt +12 -0
  162. runbooks/inventory/run_on_multi_accounts.py +211 -0
  163. runbooks/inventory/tests/common_test_data.py +3661 -0
  164. runbooks/inventory/tests/common_test_functions.py +204 -0
  165. runbooks/inventory/tests/script_test_data.py +0 -0
  166. runbooks/inventory/tests/setup.py +24 -0
  167. runbooks/inventory/tests/src.py +18 -0
  168. runbooks/inventory/tests/test_cfn_describe_stacks.py +208 -0
  169. runbooks/inventory/tests/test_ec2_describe_instances.py +162 -0
  170. runbooks/inventory/tests/test_inventory_modules.py +55 -0
  171. runbooks/inventory/tests/test_lambda_list_functions.py +86 -0
  172. runbooks/inventory/tests/test_moto_integration_example.py +273 -0
  173. runbooks/inventory/tests/test_org_list_accounts.py +49 -0
  174. runbooks/inventory/update_aws_actions.py +173 -0
  175. runbooks/inventory/update_cfn_stacksets.py +1215 -0
  176. runbooks/inventory/update_cloudwatch_logs_retention_policy.py +294 -0
  177. runbooks/inventory/update_iam_roles_cross_accounts.py +478 -0
  178. runbooks/inventory/update_s3_public_access_block.py +539 -0
  179. runbooks/inventory/utils/__init__.py +23 -0
  180. runbooks/inventory/utils/aws_helpers.py +510 -0
  181. runbooks/inventory/utils/threading_utils.py +493 -0
  182. runbooks/inventory/utils/validation.py +682 -0
  183. runbooks/inventory/verify_ec2_security_groups.py +1430 -0
  184. runbooks/main.py +785 -0
  185. runbooks/organizations/__init__.py +12 -0
  186. runbooks/organizations/manager.py +374 -0
  187. runbooks/security_baseline/README.md +324 -0
  188. runbooks/security_baseline/checklist/alternate_contacts.py +8 -1
  189. runbooks/security_baseline/checklist/bucket_public_access.py +4 -1
  190. runbooks/security_baseline/checklist/cloudwatch_alarm_configuration.py +9 -2
  191. runbooks/security_baseline/checklist/guardduty_enabled.py +9 -2
  192. runbooks/security_baseline/checklist/multi_region_instance_usage.py +5 -1
  193. runbooks/security_baseline/checklist/root_access_key.py +6 -1
  194. runbooks/security_baseline/config-origin.json +1 -1
  195. runbooks/security_baseline/config.json +1 -1
  196. runbooks/security_baseline/permission.json +1 -1
  197. runbooks/security_baseline/report_generator.py +10 -2
  198. runbooks/security_baseline/report_template_en.html +7 -7
  199. runbooks/security_baseline/report_template_jp.html +7 -7
  200. runbooks/security_baseline/report_template_kr.html +12 -12
  201. runbooks/security_baseline/report_template_vn.html +7 -7
  202. runbooks/security_baseline/requirements.txt +7 -0
  203. runbooks/security_baseline/run_script.py +8 -2
  204. runbooks/security_baseline/security_baseline_tester.py +10 -2
  205. runbooks/security_baseline/utils/common.py +5 -1
  206. runbooks/utils/__init__.py +204 -0
  207. runbooks-0.6.1.dist-info/METADATA +373 -0
  208. runbooks-0.6.1.dist-info/RECORD +237 -0
  209. {runbooks-0.2.5.dist-info → runbooks-0.6.1.dist-info}/WHEEL +1 -1
  210. runbooks-0.6.1.dist-info/entry_points.txt +7 -0
  211. runbooks-0.6.1.dist-info/licenses/LICENSE +201 -0
  212. runbooks-0.6.1.dist-info/top_level.txt +3 -0
  213. runbooks/python101/calculator.py +0 -34
  214. runbooks/python101/config.py +0 -1
  215. runbooks/python101/exceptions.py +0 -16
  216. runbooks/python101/file_manager.py +0 -218
  217. runbooks/python101/toolkit.py +0 -153
  218. runbooks-0.2.5.dist-info/METADATA +0 -439
  219. runbooks-0.2.5.dist-info/RECORD +0 -61
  220. runbooks-0.2.5.dist-info/entry_points.txt +0 -3
  221. runbooks-0.2.5.dist-info/top_level.txt +0 -1
@@ -0,0 +1,422 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ AWS VPC Inventory Collection
4
+
5
+ A comprehensive VPC discovery tool for multi-account AWS Organizations that provides
6
+ detailed network topology visibility across all accounts and regions. Supports
7
+ filtering for default VPCs to identify potential security risks.
8
+
9
+ **AWS API Mapping**: `boto3.client('ec2').describe_vpcs()`
10
+
11
+ Features:
12
+ - Multi-account VPC discovery via AWS Organizations
13
+ - Default VPC identification for security auditing
14
+ - CIDR block and association analysis
15
+ - VPC peering and gateway information
16
+ - Tag-based metadata collection
17
+ - Cross-region network topology mapping
18
+
19
+ Compatibility:
20
+ - AWS Organizations with cross-account roles
21
+ - AWS Control Tower managed accounts
22
+ - Standalone AWS accounts
23
+ - All AWS regions including opt-in regions
24
+
25
+ Example:
26
+ Discover all VPCs across organization:
27
+ ```bash
28
+ python ec2_describe_vpcs.py --profile my-org-profile
29
+ ```
30
+
31
+ Find only default VPCs for security audit:
32
+ ```bash
33
+ python ec2_describe_vpcs.py --profile my-profile --default
34
+ ```
35
+
36
+ Export VPC inventory to file:
37
+ ```bash
38
+ python ec2_describe_vpcs.py --profile my-profile \\
39
+ --save vpc_inventory.json --output json
40
+ ```
41
+
42
+ Requirements:
43
+ - IAM permissions: `ec2:DescribeVpcs`, `sts:AssumeRole`
44
+ - AWS Organizations access (for multi-account scanning)
45
+ - Python 3.8+ with required dependencies
46
+
47
+ Author:
48
+ AWS Cloud Foundations Team
49
+
50
+ Version:
51
+ 2024.01.26
52
+ """
53
+
54
+ import logging
55
+ import sys
56
+ from queue import Queue
57
+
58
+ # from tqdm.auto import tqdm
59
+ from threading import Thread
60
+ from time import time
61
+
62
+ import Inventory_Modules
63
+ from ArgumentsClass import CommonArguments
64
+ from botocore.exceptions import ClientError
65
+ from colorama import Fore, init
66
+ from Inventory_Modules import display_results, get_all_credentials
67
+
68
+ init()
69
+ __version__ = "2024.01.26"
70
+
71
+
72
+ ##########################
73
+ def parse_args(args):
74
+ """
75
+ Parse and validate command-line arguments for VPC network topology discovery.
76
+
77
+ Configures the argument parser with VPC-specific options including default VPC
78
+ detection for security auditing and comprehensive network inventory capabilities.
79
+ Uses the standardized CommonArguments framework for consistency.
80
+
81
+ Args:
82
+ args (list): Command-line arguments to parse (typically sys.argv[1:])
83
+
84
+ Returns:
85
+ argparse.Namespace: Parsed arguments containing:
86
+ - Profiles: AWS profiles for multi-account network discovery
87
+ - Regions: Target AWS regions for VPC enumeration
88
+ - AccessRoles: Cross-account roles for Organizations access
89
+ - pDefault: CRITICAL security flag for default VPC identification
90
+ - RootOnly: Limit to Organization Management Accounts
91
+ - Filename: Output file prefix for network topology export
92
+ - Other standard framework arguments
93
+
94
+ Security-Critical Argument:
95
+ --default: Identifies default VPCs which represent significant security risks:
96
+ - Often have overly permissive security groups
97
+ - May violate network segmentation policies
98
+ - Should be replaced with purpose-built VPCs
99
+ - Critical for compliance auditing (PCI DSS, SOC2)
100
+ - Essential for CIS benchmark compliance
101
+
102
+ Network Architecture Use Cases:
103
+ - Network topology mapping: Complete VPC inventory
104
+ - Security auditing: Default VPC identification and remediation
105
+ - CIDR planning: IP address space utilization analysis
106
+ - Compliance validation: Network segmentation verification
107
+ - Migration planning: Cross-account network architecture assessment
108
+ """
109
+ parser = CommonArguments()
110
+ parser.my_parser.description = "We're going to find all vpcs within any of the accounts and regions we have access to, given the profile(s) provided."
111
+ parser.multiprofile()
112
+ parser.multiregion()
113
+ parser.extendedargs()
114
+ parser.rolestouse()
115
+ parser.rootOnly()
116
+ parser.timing()
117
+ parser.save_to_file()
118
+ parser.verbosity()
119
+ parser.version(__version__)
120
+ parser.my_parser.add_argument(
121
+ "--default",
122
+ dest="pDefault",
123
+ metavar="Looking for default VPCs only",
124
+ action="store_const",
125
+ default=False,
126
+ const=True,
127
+ help="Flag to determine whether we're looking for default VPCs only.",
128
+ )
129
+ return parser.my_parser.parse_args(args)
130
+
131
+
132
+ def find_all_vpcs(fAllCredentials, fDefaultOnly=False):
133
+ """
134
+ Execute multi-threaded VPC discovery across AWS accounts and regions.
135
+
136
+ This is the core network topology discovery engine that performs concurrent
137
+ VPC enumeration across all provided AWS accounts and regions. Essential for
138
+ understanding network architecture, CIDR utilization, and security posture.
139
+
140
+ Args:
141
+ fAllCredentials (list): List of credential dictionaries containing:
142
+ - AccountId: AWS account identifier
143
+ - Region: AWS region name
144
+ - AccessKeyId, SecretAccessKey, SessionToken: AWS credentials
145
+ - MgmtAccount: Management account identifier
146
+ - Success: Boolean flag indicating credential validation status
147
+
148
+ fDefaultOnly (bool, optional): Focus discovery on default VPCs only.
149
+ Critical for security auditing as default VPCs often violate
150
+ network security policies and compliance requirements.
151
+
152
+ Returns:
153
+ list: Comprehensive VPC inventory with network metadata:
154
+ - VpcId: AWS VPC identifier
155
+ - VpcName: VPC name from tags (or "No name defined")
156
+ - CIDR: VPC CIDR block (handles multiple CIDRs per VPC)
157
+ - IsDefault: Boolean indicating if VPC is account default
158
+ - AccountId: Source AWS account
159
+ - Region: Source AWS region
160
+ - MgmtAccount: Management account identifier
161
+
162
+ Threading Architecture:
163
+ - Uses Queue for thread-safe work distribution
164
+ - Worker thread pool for concurrent VPC discovery
165
+ - Progress tracking for large-scale network inventory
166
+ - Comprehensive error handling for account access failures
167
+
168
+ Network Analysis Features:
169
+ - CIDR block enumeration (handles secondary CIDR associations)
170
+ - Default VPC identification for security compliance
171
+ - Tag-based VPC naming and categorization
172
+ - Cross-account network topology mapping
173
+ - Regional network architecture visibility
174
+
175
+ Security Implications:
176
+ - Default VPCs represent significant security risks
177
+ - Often have permissive default security groups
178
+ - May violate network segmentation requirements
179
+ - Critical for PCI DSS and SOC2 compliance validation
180
+ - Essential for Zero Trust architecture assessment
181
+
182
+ Enterprise Use Cases:
183
+ - Network architecture documentation
184
+ - CIDR space planning and IP address management
185
+ - Compliance auditing and remediation planning
186
+ - Multi-account network segmentation validation
187
+ - Cloud migration network assessment
188
+ """
189
+
190
+ class FindVPCs(Thread):
191
+ """
192
+ Worker thread for concurrent VPC discovery and network topology analysis.
193
+
194
+ Each worker thread processes credential sets from the shared queue,
195
+ calls AWS EC2 VPC APIs to discover network infrastructure, and performs
196
+ detailed CIDR and default VPC analysis for security assessment.
197
+
198
+ Network Discovery Capabilities:
199
+ - VPC enumeration with metadata extraction
200
+ - CIDR block association analysis
201
+ - Default VPC identification for security auditing
202
+ - Tag-based VPC naming and categorization
203
+ - Cross-account network topology mapping
204
+ """
205
+
206
+ def __init__(self, queue):
207
+ """
208
+ Initialize worker thread with reference to shared work queue.
209
+
210
+ Args:
211
+ queue (Queue): Thread-safe queue containing VPC discovery work items
212
+ """
213
+ Thread.__init__(self)
214
+ self.queue = queue
215
+
216
+ def run(self):
217
+ """
218
+ Main worker thread execution loop for VPC network discovery.
219
+
220
+ Continuously processes credential sets from queue, performs VPC
221
+ discovery via AWS EC2 APIs, and aggregates network topology data
222
+ with comprehensive CIDR and security analysis.
223
+ """
224
+ while True:
225
+ # Get VPC discovery work item from thread-safe queue
226
+ c_account_credentials, c_default, c_PlaceCount = self.queue.get()
227
+ logging.info(f"De-queued info for account number {c_account_credentials['AccountId']}")
228
+
229
+ try:
230
+ # Call AWS EC2 API to discover VPCs in this account/region
231
+ # find_account_vpcs2() handles DescribeVpcs API with optional default filtering
232
+ Vpcs = Inventory_Modules.find_account_vpcs2(c_account_credentials, c_default)
233
+
234
+ logging.info(
235
+ f"Account: {c_account_credentials['AccountId']} Region: {c_account_credentials['Region']} | Found {len(Vpcs['Vpcs'])} VPCs"
236
+ )
237
+ # Process discovered VPCs with comprehensive network metadata extraction
238
+ if "Vpcs" in Vpcs.keys() and len(Vpcs["Vpcs"]) > 0:
239
+ for y in range(len(Vpcs["Vpcs"])):
240
+ # Initialize VPC metadata with default values
241
+ VpcName = "No name defined" # Fallback for untagged VPCs
242
+ VpcId = Vpcs["Vpcs"][y]["VpcId"]
243
+ IsDefault = Vpcs["Vpcs"][y]["IsDefault"] # Critical for security assessment
244
+ CIDRBlockAssociationSet = Vpcs["Vpcs"][y]["CidrBlockAssociationSet"]
245
+
246
+ # Extract VPC name from tags for network documentation
247
+ # Proper VPC naming is essential for network governance
248
+ if "Tags" in Vpcs["Vpcs"][y]:
249
+ for z in range(len(Vpcs["Vpcs"][y]["Tags"])):
250
+ if Vpcs["Vpcs"][y]["Tags"][z]["Key"] == "Name":
251
+ VpcName = Vpcs["Vpcs"][y]["Tags"][z]["Value"]
252
+
253
+ # Handle multiple CIDR block associations per VPC
254
+ # AWS supports secondary CIDR blocks for IP space expansion
255
+ # Each CIDR gets its own record for accurate IP space tracking
256
+ for _ in range(len(CIDRBlockAssociationSet)):
257
+ # Create individual record for each CIDR association
258
+ # This enables precise CIDR space analysis and planning
259
+ AllVPCs.append(
260
+ {
261
+ # Organizational context
262
+ "MgmtAccount": c_account_credentials["MgmtAccount"],
263
+ "AccountId": c_account_credentials["AccountId"],
264
+ "Region": c_account_credentials["Region"],
265
+ # Network topology data
266
+ "CIDR": CIDRBlockAssociationSet[_]["CidrBlock"],
267
+ "VpcId": VpcId,
268
+ "VpcName": VpcName,
269
+ # Security-critical default VPC flag
270
+ "IsDefault": IsDefault,
271
+ }
272
+ )
273
+ else:
274
+ # No VPCs found in this account/region combination
275
+ continue
276
+ except KeyError as my_Error:
277
+ # Handle credential or account access configuration errors
278
+ logging.error(f"Account Access failed - trying to access {c_account_credentials['AccountId']}")
279
+ logging.info(f"Actual Error: {my_Error}")
280
+ # Continue processing other accounts despite this failure
281
+ pass
282
+
283
+ except AttributeError as my_Error:
284
+ # Handle profile configuration or credential format errors
285
+ logging.error(f"Error: Likely that one of the supplied profiles was wrong")
286
+ logging.warning(my_Error)
287
+ continue
288
+
289
+ except ClientError as my_Error:
290
+ # Handle AWS API authentication and authorization errors
291
+ if "AuthFailure" in str(my_Error):
292
+ logging.error(
293
+ f"Authorization Failure accessing account {c_account_credentials['AccountId']} in {c_account_credentials['Region']} region"
294
+ )
295
+ logging.warning(
296
+ f"It's possible that the region {c_account_credentials['Region']} hasn't been opted-into"
297
+ )
298
+ continue
299
+ else:
300
+ # Handle API throttling and other service errors
301
+ logging.error(f"Error: Likely throttling errors from too much activity")
302
+ logging.warning(my_Error)
303
+ continue
304
+
305
+ finally:
306
+ # Always mark work item as complete for queue management
307
+ self.queue.task_done()
308
+
309
+ ###########
310
+
311
+ checkqueue = Queue()
312
+
313
+ AllVPCs = []
314
+ PlaceCount = 0
315
+ WorkerThreads = min(len(fAllCredentials), 25)
316
+
317
+ worker_threads = []
318
+ for x in range(WorkerThreads):
319
+ worker = FindVPCs(checkqueue)
320
+ # Setting daemon to False for proper cleanup
321
+ worker.daemon = False
322
+ worker.start()
323
+ worker_threads.append(worker)
324
+
325
+ for credential in fAllCredentials:
326
+ logging.info(f"Beginning to queue data - starting with {credential['AccountId']}")
327
+ print(
328
+ f"{ERASE_LINE}Checking {credential['AccountId']} in region {credential['Region']} - {PlaceCount + 1} / {len(fAllCredentials)}",
329
+ end="\r",
330
+ )
331
+ # for region in fRegionList:
332
+ try:
333
+ # I don't know why - but double parens are necessary below. If you remove them, only the first parameter is queued.
334
+ checkqueue.put((credential, fDefaultOnly, PlaceCount))
335
+ logging.info(f"Put credential: {credential}, Default: {fDefaultOnly}")
336
+ PlaceCount += 1
337
+ except ClientError as my_Error:
338
+ if "AuthFailure" in str(my_Error):
339
+ logging.error(
340
+ f"Authorization Failure accessing account {credential['AccountId']} in {credential['Region']} region"
341
+ )
342
+ logging.warning(f"It's possible that the region {credential['Region']} hasn't been opted-into")
343
+ pass
344
+ checkqueue.join()
345
+ return AllVPCs
346
+
347
+
348
+ ##########################
349
+ if __name__ == "__main__":
350
+ args = parse_args(sys.argv[1:])
351
+ pProfiles = args.Profiles
352
+ pRegionList = args.Regions
353
+ pAccounts = args.Accounts
354
+ pRoles = args.AccessRoles
355
+ pSkipProfiles = args.SkipProfiles
356
+ pSkipAccounts = args.SkipAccounts
357
+ pRootOnly = args.RootOnly
358
+ pTiming = args.Time
359
+ pFilename = args.Filename
360
+ pDefault = args.pDefault
361
+ verbose = args.loglevel
362
+ logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)30s() ] %(message)s")
363
+
364
+ ERASE_LINE = "\x1b[2K"
365
+
366
+ begin_time = time()
367
+
368
+ NumVpcsFound = 0
369
+ NumRegions = 0
370
+ if pProfiles is not None:
371
+ print(f"Checking for VPCs in profile{'s' if len(pProfiles) > 1 else ''} {pProfiles}")
372
+ else:
373
+ print(f"Checking for VPCs in default profile")
374
+
375
+ # NumOfRootProfiles = 0
376
+ # Get credentials
377
+ AllCredentials = get_all_credentials(
378
+ pProfiles, pTiming, pSkipProfiles, pSkipAccounts, pRootOnly, pAccounts, pRegionList, pRoles
379
+ )
380
+ AllRegionsList = list(set([x["Region"] for x in AllCredentials]))
381
+ AllAccountList = list(set([x["AccountId"] for x in AllCredentials]))
382
+ # Find the VPCs
383
+ All_VPCs_Found = find_all_vpcs(AllCredentials, pDefault)
384
+ # Display results
385
+ display_dict = {
386
+ "MgmtAccount": {"DisplayOrder": 1, "Heading": "Mgmt Acct"},
387
+ "AccountId": {"DisplayOrder": 2, "Heading": "Acct Number"},
388
+ "Region": {"DisplayOrder": 3, "Heading": "Region"},
389
+ "VpcName": {"DisplayOrder": 4, "Heading": "VPC Name"},
390
+ "CIDR": {"DisplayOrder": 5, "Heading": "CIDR Block"},
391
+ "IsDefault": {"DisplayOrder": 6, "Heading": "Default VPC", "Condition": [True, 1, "1"]},
392
+ "VpcId": {"DisplayOrder": 7, "Heading": "VPC Id"},
393
+ }
394
+
395
+ logging.info(f"# of Regions: {len(AllRegionsList)}")
396
+ # logging.info(f"# of Management Accounts: {NumOfRootProfiles}")
397
+ logging.info(f"# of Child Accounts: {len(AllAccountList)}")
398
+
399
+ sorted_AllVPCs = sorted(
400
+ All_VPCs_Found, key=lambda d: (d["MgmtAccount"], d["AccountId"], d["Region"], d["VpcName"], d["CIDR"])
401
+ )
402
+ print()
403
+ display_results(sorted_AllVPCs, display_dict, None, pFilename)
404
+
405
+ # Threading cleanup is handled within find_all_vpcs function
406
+
407
+ print()
408
+ # checkqueue.join() marks all of the threads as done - so Checking is done
409
+ logging.info(f"Threads all done - took {time() - begin_time:.2f} seconds")
410
+
411
+ if pTiming:
412
+ print(ERASE_LINE)
413
+ print(f"{Fore.GREEN}This script took {time() - begin_time:.2f} seconds{Fore.RESET}")
414
+ print(ERASE_LINE)
415
+ # Had to do this, because some of the VPCs that show up in the "sorted_AllVPCs" list are actually the same VPC, with a different CIDR range.
416
+ Num_of_unique_VPCs = len(set([x["VpcId"] for x in sorted_AllVPCs]))
417
+ print(
418
+ f"Found {Num_of_unique_VPCs}{' default' if pDefault else ''} Vpcs across {len(AllAccountList)} accounts across {len(AllRegionsList)} regions"
419
+ )
420
+ print()
421
+ print("Thank you for using this script.")
422
+ print()
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import logging
4
+ import sys
5
+
6
+ import boto3
7
+ import Inventory_Modules
8
+ import simplejson as json
9
+ from account_class import aws_acct_access
10
+ from ArgumentsClass import CommonArguments
11
+ from botocore.exceptions import ClientError
12
+
13
+ __version__ = "2023.05.04"
14
+
15
+ parser = CommonArguments()
16
+ parser.singleprofile()
17
+ parser.singleregion()
18
+ parser.verbosity()
19
+ parser.version(__version__)
20
+ parser.my_parser.add_argument(
21
+ "-R",
22
+ "--access_rolename",
23
+ dest="pAccessRole",
24
+ default="AWSCloudFormationStackSetExecutionRole",
25
+ metavar="role to use for access to child accounts",
26
+ help="This parameter specifies the role that will allow this script to have access to the children accounts.",
27
+ )
28
+ parser.my_parser.add_argument(
29
+ "-t",
30
+ "--target_rolename",
31
+ dest="pTargetRole",
32
+ default="AWSCloudFormationStackSetExecutionRole",
33
+ metavar="role to change",
34
+ help="This parameter specifies the role to have its Trust Policy changed.",
35
+ )
36
+ parser.my_parser.add_argument(
37
+ "+f",
38
+ "--fix",
39
+ "+fix",
40
+ dest="pFix",
41
+ action="store_const",
42
+ const=True,
43
+ default=False,
44
+ help="This parameter determines whether to make any changes in child accounts.",
45
+ )
46
+ parser.my_parser.add_argument(
47
+ "+l",
48
+ "--lock",
49
+ "+lock",
50
+ dest="pLock",
51
+ action="store_const",
52
+ const=True,
53
+ default=False,
54
+ help="This parameter determines whether to lock the Trust Policy.",
55
+ )
56
+ parser.my_parser.add_argument(
57
+ "-s",
58
+ "--safety",
59
+ dest="pSafety",
60
+ action="store_const",
61
+ const=False,
62
+ default=True,
63
+ help="Adding this parameter will 'remove the safety' - by not including the principle running this script, which might mean you get locked out of making further changes.",
64
+ )
65
+ args = parser.my_parser.parse_args()
66
+
67
+ pProfile = args.Profile
68
+ pTargetRole = args.pTargetRole
69
+ pAccessRole = args.pAccessRole
70
+ pLock = args.pLock
71
+ pSafety = args.pSafety
72
+ pFix = args.pFix
73
+ verbose = args.loglevel
74
+ logging.basicConfig(level=args.loglevel, format="[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s")
75
+
76
+ aws_acct = aws_acct_access(pProfile)
77
+
78
+ if not aws_acct.AccountType.lower() == "root":
79
+ print()
80
+ print(f"The profile {pProfile} does not represent an Org")
81
+ print("This script only works with org accounts.")
82
+ print()
83
+ sys.exit(1)
84
+ ##########################
85
+ ERASE_LINE = "\x1b[2K"
86
+ ##########################
87
+
88
+ print(f"We're using the {pAccessRole} role to gain access to the child accounts")
89
+ print(f"We're targeting the {pTargetRole} role to change its Trust Policy")
90
+
91
+ """
92
+ 1. Collect SSM parameters with the ARNs that should be in the permission
93
+ 2. Create the TrustPolicy in JSON
94
+ 3. Get a listing of all accounts that need to be updated
95
+ 4. Connect to each account, and update the existing trust policy with the new policy
96
+ """
97
+ # 1. Collect parameters with the ARNs that should be in the permission
98
+ # lock_down_arns_list=[]
99
+ allowed_arns = []
100
+ ssm_client = aws_acct.session.client("ssm")
101
+ param_list = ssm_client.describe_parameters(
102
+ ParameterFilters=[{"Key": "Name", "Option": "Contains", "Values": ["lock_down_role_arns_list"]}]
103
+ )["Parameters"]
104
+ if len(param_list) == 0:
105
+ print("You need to set the region (-r|--region) to the default region where the SSM parameters are stored.")
106
+ print("Otherwise, with no *allowed* arns, we would lock everything out from this role.")
107
+ print("Exiting...")
108
+ sys.exit(2)
109
+ for i in param_list:
110
+ response = param = ssm_client.get_parameter(Name=i["Name"])
111
+ logging.info(f"Adding {response['Parameter']['Value']} to the list for i: {i['Name']}")
112
+ allowed_arns.append(response["Parameter"]["Value"])
113
+
114
+ # 1.5 Find who is running the script and add their credential as a safety
115
+ Creds = Inventory_Modules.find_calling_identity(pProfile)
116
+ if pSafety:
117
+ allowed_arns.append(Creds["Arn"])
118
+ # 2. Create the Trust Policy in JSON
119
+
120
+ if pLock:
121
+ if pSafety and pFix:
122
+ logging.error("Locking down the Trust Policy to *only* the Lambda functions.")
123
+ elif pFix:
124
+ logging.error(f"Locking down the Trust Policy to the Lambda functions and {Creds['Arn']}.")
125
+ else:
126
+ logging.critical(
127
+ "While you asked us to lock things down, You didn't use the '+f' parameter, so we're not changing a thing."
128
+ )
129
+ Trust_Policy = {
130
+ "Version": "2012-10-17",
131
+ "Statement": [
132
+ {"Sid": "LambdaAccess", "Effect": "Allow", "Principal": {"AWS": allowed_arns}, "Action": "sts:AssumeRole"}
133
+ ],
134
+ }
135
+ else:
136
+ Trust_Policy = {
137
+ "Version": "2012-10-17",
138
+ "Statement": [
139
+ {"Sid": "LambdaAccess", "Effect": "Allow", "Principal": {"AWS": allowed_arns}, "Action": "sts:AssumeRole"},
140
+ {
141
+ "Sid": "DevAccess",
142
+ "Effect": "Allow",
143
+ "Principal": {"AWS": [f"arn:aws:iam::{aws_acct.MgmtAccount}:root"]},
144
+ "Action": "sts:AssumeRole",
145
+ },
146
+ ],
147
+ }
148
+ Trust_Policy_json = json.dumps(Trust_Policy)
149
+ # 3. Get a listing of all accounts that need to be updated and then ...
150
+
151
+
152
+ # 4. Connect to each account, and detach the existing policy, and apply the new policy
153
+ sts_client = aws_acct.session.client("sts")
154
+ TrustPoliciesChanged = 0
155
+ ErroredAccounts = []
156
+ for acct in aws_acct.ChildAccounts:
157
+ ConnectionSuccess = False
158
+ try:
159
+ role_arn = f"arn:aws:iam::{acct['AccountId']}:role/{pAccessRole}"
160
+ account_credentials = sts_client.assume_role(RoleArn=role_arn, RoleSessionName="RegistrationScript")[
161
+ "Credentials"
162
+ ]
163
+ account_credentials["Account"] = acct["AccountId"]
164
+ logging.warning(f"Accessed Account {acct['AccountId']} using rolename {pAccessRole}")
165
+ ConnectionSuccess = True
166
+ except ClientError as my_Error:
167
+ logging.error(
168
+ f"Account {acct['AccountId']}, role {pTargetRole} was unavailable to change, so we couldn't access the role's Trust Policy"
169
+ )
170
+ logging.warning(my_Error)
171
+ ErroredAccounts.append(acct["AccountId"])
172
+ pass
173
+ if ConnectionSuccess:
174
+ try:
175
+ # detach policy from the role and attach the new policy
176
+ iam_session = boto3.Session(
177
+ aws_access_key_id=account_credentials["AccessKeyId"],
178
+ aws_secret_access_key=account_credentials["SecretAccessKey"],
179
+ aws_session_token=account_credentials["SessionToken"],
180
+ )
181
+ iam_client = iam_session.client("iam")
182
+ trustpolicyexisting = iam_client.get_role(RoleName=pTargetRole)
183
+ logging.info(
184
+ "Found Trust Policy %s in account %s for role %s"
185
+ % (json.dumps(trustpolicyexisting["Role"]["AssumeRolePolicyDocument"]), acct["AccountId"], pTargetRole)
186
+ )
187
+ if pFix:
188
+ trustpolicyupdate = iam_client.update_assume_role_policy(
189
+ RoleName=pTargetRole, PolicyDocument=Trust_Policy_json
190
+ )
191
+ TrustPoliciesChanged += 1
192
+ logging.error(f"Updated Trust Policy in Account {acct['AccountId']} for role {pTargetRole}")
193
+ trustpolicyexisting = iam_client.get_role(RoleName=pTargetRole)
194
+ logging.info(
195
+ "Updated Trust Policy %s in account %s for role %s"
196
+ % (
197
+ json.dumps(trustpolicyexisting["Role"]["AssumeRolePolicyDocument"]),
198
+ acct["AccountId"],
199
+ pTargetRole,
200
+ )
201
+ )
202
+ else:
203
+ logging.error(f"Account {acct['AccountId']} - no changes made")
204
+ except ClientError as my_Error:
205
+ logging.warning(my_Error)
206
+ pass
207
+
208
+ print(ERASE_LINE)
209
+ print(f"We found {len(aws_acct.ChildAccounts)} accounts under your organization")
210
+ if pLock and pFix:
211
+ print(f"We locked {TrustPoliciesChanged} Trust Policies")
212
+ elif not pLock and pFix:
213
+ print(f"We unlocked {TrustPoliciesChanged} Trust Policies")
214
+ else:
215
+ print(f"We didn't change {TrustPoliciesChanged} Trust Policies")
216
+ if len(ErroredAccounts) > 0:
217
+ print(f"We weren't able to access {len(ErroredAccounts)} accounts.")
218
+ if verbose < 50:
219
+ print("Here are the accounts that were not updated")
220
+ for i in ErroredAccounts:
221
+ print(i)
222
+ print()
223
+ print("Thanks for using the tool.")
224
+ print()
@@ -0,0 +1,24 @@
1
+ """
2
+ Data models for AWS inventory system.
3
+
4
+ This module provides Pydantic-based models for representing AWS accounts,
5
+ resources, and inventory results with proper validation and serialization.
6
+
7
+ Models:
8
+ - account: AWS account representation and organization structure
9
+ - resource: Individual AWS resource models with metadata
10
+ - inventory: Inventory collection results and aggregations
11
+ """
12
+
13
+ from runbooks.inventory.models.account import AWSAccount, OrganizationAccount
14
+ from runbooks.inventory.models.inventory import InventoryMetadata, InventoryResult
15
+ from runbooks.inventory.models.resource import AWSResource, ResourceMetadata
16
+
17
+ __all__ = [
18
+ "AWSAccount",
19
+ "OrganizationAccount",
20
+ "AWSResource",
21
+ "ResourceMetadata",
22
+ "InventoryResult",
23
+ "InventoryMetadata",
24
+ ]