runbooks 0.7.0__py3-none-any.whl → 0.7.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 (132) hide show
  1. runbooks/__init__.py +87 -37
  2. runbooks/cfat/README.md +300 -49
  3. runbooks/cfat/__init__.py +2 -2
  4. runbooks/finops/__init__.py +1 -1
  5. runbooks/finops/cli.py +1 -1
  6. runbooks/inventory/collectors/__init__.py +8 -0
  7. runbooks/inventory/collectors/aws_management.py +791 -0
  8. runbooks/inventory/collectors/aws_networking.py +3 -3
  9. runbooks/main.py +3389 -782
  10. runbooks/operate/__init__.py +207 -0
  11. runbooks/operate/base.py +311 -0
  12. runbooks/operate/cloudformation_operations.py +619 -0
  13. runbooks/operate/cloudwatch_operations.py +496 -0
  14. runbooks/operate/dynamodb_operations.py +812 -0
  15. runbooks/operate/ec2_operations.py +926 -0
  16. runbooks/operate/iam_operations.py +569 -0
  17. runbooks/operate/s3_operations.py +1211 -0
  18. runbooks/operate/tagging_operations.py +655 -0
  19. runbooks/remediation/CLAUDE.md +100 -0
  20. runbooks/remediation/DOME9.md +218 -0
  21. runbooks/remediation/README.md +26 -0
  22. runbooks/remediation/Tests/__init__.py +0 -0
  23. runbooks/remediation/Tests/update_policy.py +74 -0
  24. runbooks/remediation/__init__.py +95 -0
  25. runbooks/remediation/acm_cert_expired_unused.py +98 -0
  26. runbooks/remediation/acm_remediation.py +875 -0
  27. runbooks/remediation/api_gateway_list.py +167 -0
  28. runbooks/remediation/base.py +643 -0
  29. runbooks/remediation/cloudtrail_remediation.py +908 -0
  30. runbooks/remediation/cloudtrail_s3_modifications.py +296 -0
  31. runbooks/remediation/cognito_active_users.py +78 -0
  32. runbooks/remediation/cognito_remediation.py +856 -0
  33. runbooks/remediation/cognito_user_password_reset.py +163 -0
  34. runbooks/remediation/commons.py +455 -0
  35. runbooks/remediation/dynamodb_optimize.py +155 -0
  36. runbooks/remediation/dynamodb_remediation.py +744 -0
  37. runbooks/remediation/dynamodb_server_side_encryption.py +108 -0
  38. runbooks/remediation/ec2_public_ips.py +134 -0
  39. runbooks/remediation/ec2_remediation.py +892 -0
  40. runbooks/remediation/ec2_subnet_disable_auto_ip_assignment.py +72 -0
  41. runbooks/remediation/ec2_unattached_ebs_volumes.py +448 -0
  42. runbooks/remediation/ec2_unused_security_groups.py +202 -0
  43. runbooks/remediation/kms_enable_key_rotation.py +651 -0
  44. runbooks/remediation/kms_remediation.py +717 -0
  45. runbooks/remediation/lambda_list.py +243 -0
  46. runbooks/remediation/lambda_remediation.py +971 -0
  47. runbooks/remediation/multi_account.py +569 -0
  48. runbooks/remediation/rds_instance_list.py +199 -0
  49. runbooks/remediation/rds_remediation.py +873 -0
  50. runbooks/remediation/rds_snapshot_list.py +192 -0
  51. runbooks/remediation/requirements.txt +118 -0
  52. runbooks/remediation/s3_block_public_access.py +159 -0
  53. runbooks/remediation/s3_bucket_public_access.py +143 -0
  54. runbooks/remediation/s3_disable_static_website_hosting.py +74 -0
  55. runbooks/remediation/s3_downloader.py +215 -0
  56. runbooks/remediation/s3_enable_access_logging.py +562 -0
  57. runbooks/remediation/s3_encryption.py +526 -0
  58. runbooks/remediation/s3_force_ssl_secure_policy.py +143 -0
  59. runbooks/remediation/s3_list.py +141 -0
  60. runbooks/remediation/s3_object_search.py +201 -0
  61. runbooks/remediation/s3_remediation.py +816 -0
  62. runbooks/remediation/scan_for_phrase.py +425 -0
  63. runbooks/remediation/workspaces_list.py +220 -0
  64. runbooks/security/__init__.py +9 -10
  65. runbooks/security/security_baseline_tester.py +4 -2
  66. runbooks-0.7.6.dist-info/METADATA +608 -0
  67. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/RECORD +84 -76
  68. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/entry_points.txt +0 -1
  69. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/top_level.txt +0 -1
  70. jupyter-agent/.env +0 -2
  71. jupyter-agent/.env.template +0 -2
  72. jupyter-agent/.gitattributes +0 -35
  73. jupyter-agent/.gradio/certificate.pem +0 -31
  74. jupyter-agent/README.md +0 -16
  75. jupyter-agent/__main__.log +0 -8
  76. jupyter-agent/app.py +0 -256
  77. jupyter-agent/cloudops-agent.png +0 -0
  78. jupyter-agent/ds-system-prompt.txt +0 -154
  79. jupyter-agent/jupyter-agent.png +0 -0
  80. jupyter-agent/llama3_template.jinja +0 -123
  81. jupyter-agent/requirements.txt +0 -9
  82. jupyter-agent/tmp/4ojbs8a02ir/jupyter-agent.ipynb +0 -68
  83. jupyter-agent/tmp/cm5iasgpm3p/jupyter-agent.ipynb +0 -91
  84. jupyter-agent/tmp/crqbsseag5/jupyter-agent.ipynb +0 -91
  85. jupyter-agent/tmp/hohanq1u097/jupyter-agent.ipynb +0 -57
  86. jupyter-agent/tmp/jns1sam29wm/jupyter-agent.ipynb +0 -53
  87. jupyter-agent/tmp/jupyter-agent.ipynb +0 -27
  88. jupyter-agent/utils.py +0 -409
  89. runbooks/aws/__init__.py +0 -58
  90. runbooks/aws/dynamodb_operations.py +0 -231
  91. runbooks/aws/ec2_copy_image_cross-region.py +0 -195
  92. runbooks/aws/ec2_describe_instances.py +0 -202
  93. runbooks/aws/ec2_ebs_snapshots_delete.py +0 -186
  94. runbooks/aws/ec2_run_instances.py +0 -213
  95. runbooks/aws/ec2_start_stop_instances.py +0 -212
  96. runbooks/aws/ec2_terminate_instances.py +0 -143
  97. runbooks/aws/ec2_unused_eips.py +0 -196
  98. runbooks/aws/ec2_unused_volumes.py +0 -188
  99. runbooks/aws/s3_create_bucket.py +0 -142
  100. runbooks/aws/s3_list_buckets.py +0 -152
  101. runbooks/aws/s3_list_objects.py +0 -156
  102. runbooks/aws/s3_object_operations.py +0 -183
  103. runbooks/aws/tagging_lambda_handler.py +0 -183
  104. runbooks/inventory/FAILED_SCRIPTS_TROUBLESHOOTING.md +0 -619
  105. runbooks/inventory/PASSED_SCRIPTS_GUIDE.md +0 -738
  106. runbooks/inventory/aws_organization.png +0 -0
  107. runbooks/inventory/cfn_move_stack_instances.py +0 -1526
  108. runbooks/inventory/delete_s3_buckets_objects.py +0 -169
  109. runbooks/inventory/lockdown_cfn_stackset_role.py +0 -224
  110. runbooks/inventory/update_aws_actions.py +0 -173
  111. runbooks/inventory/update_cfn_stacksets.py +0 -1215
  112. runbooks/inventory/update_cloudwatch_logs_retention_policy.py +0 -294
  113. runbooks/inventory/update_iam_roles_cross_accounts.py +0 -478
  114. runbooks/inventory/update_s3_public_access_block.py +0 -539
  115. runbooks/organizations/__init__.py +0 -12
  116. runbooks/organizations/manager.py +0 -374
  117. runbooks-0.7.0.dist-info/METADATA +0 -375
  118. /runbooks/inventory/{tests → Tests}/common_test_data.py +0 -0
  119. /runbooks/inventory/{tests → Tests}/common_test_functions.py +0 -0
  120. /runbooks/inventory/{tests → Tests}/script_test_data.py +0 -0
  121. /runbooks/inventory/{tests → Tests}/setup.py +0 -0
  122. /runbooks/inventory/{tests → Tests}/src.py +0 -0
  123. /runbooks/inventory/{tests/test_inventory_modules.py → Tests/test_Inventory_Modules.py} +0 -0
  124. /runbooks/inventory/{tests → Tests}/test_cfn_describe_stacks.py +0 -0
  125. /runbooks/inventory/{tests → Tests}/test_ec2_describe_instances.py +0 -0
  126. /runbooks/inventory/{tests → Tests}/test_lambda_list_functions.py +0 -0
  127. /runbooks/inventory/{tests → Tests}/test_moto_integration_example.py +0 -0
  128. /runbooks/inventory/{tests → Tests}/test_org_list_accounts.py +0 -0
  129. /runbooks/inventory/{Inventory_Modules.py → inventory_modules.py} +0 -0
  130. /runbooks/{aws → operate}/tags.json +0 -0
  131. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/WHEEL +0 -0
  132. {runbooks-0.7.0.dist-info → runbooks-0.7.6.dist-info}/licenses/LICENSE +0 -0
@@ -1,539 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- AWS S3 Public Access Block Configuration Management Tool
4
-
5
- A critical security tool for managing S3 public access block settings across
6
- multi-account AWS Organizations. Essential for enforcing organizational security
7
- policies and preventing accidental public data exposure.
8
-
9
- **AWS API Mapping**:
10
- - `boto3.client('s3control').put_public_access_block()`
11
- - `boto3.client('s3control').get_public_access_block()`
12
-
13
- **SECURITY CRITICAL**: This script modifies S3 security configurations that
14
- protect against data breaches and compliance violations:
15
-
16
- Public Access Block Settings:
17
- - BlockPublicAcls: Blocks public ACLs on buckets and objects
18
- - IgnorePublicAcls: Ignores existing public ACLs
19
- - BlockPublicPolicy: Blocks public bucket policies
20
- - RestrictPublicBuckets: Restricts public bucket access
21
-
22
- Security Benefits:
23
- - Prevents accidental public data exposure
24
- - Enforces organizational security policies
25
- - Maintains compliance with data protection regulations
26
- - Provides centralized security governance
27
- - Reduces risk of data breaches and incidents
28
-
29
- Compliance Frameworks:
30
- - PCI DSS: Data protection requirements
31
- - GDPR: Privacy and data security mandates
32
- - SOC 2: Security and availability controls
33
- - HIPAA: Healthcare data protection
34
- - SOX: Financial data security requirements
35
-
36
- Compatibility:
37
- - AWS Organizations with cross-account roles
38
- - AWS Control Tower managed accounts
39
- - Standalone AWS accounts
40
- - Account-level S3 configuration management
41
-
42
- Example:
43
- Apply public access block to organization:
44
- ```bash
45
- python update_s3_public_access_block.py --profile org-profile --no-dry-run
46
- ```
47
-
48
- Dry-run mode (default - no changes made):
49
- ```bash
50
- python update_s3_public_access_block.py --profile org-profile
51
- ```
52
-
53
- Target specific accounts from file:
54
- ```bash
55
- python update_s3_public_access_block.py --profile org-profile \
56
- --file account_list.txt --no-dry-run
57
- ```
58
-
59
- Requirements:
60
- - IAM permissions: `s3:PutAccountPublicAccessBlock`, `s3:GetAccountPublicAccessBlock`, `sts:AssumeRole`
61
- - AWS Organizations access (for multi-account operations)
62
- - Python 3.8+ with required dependencies
63
-
64
- Author:
65
- AWS Cloud Foundations Team
66
-
67
- Version:
68
- 2024.04.24
69
- """
70
-
71
- import logging
72
- import sys
73
- from os.path import split
74
- from time import time
75
-
76
- import boto3
77
- from account_class import aws_acct_access
78
- from ArgumentsClass import CommonArguments
79
- from botocore.exceptions import ClientError, ProfileNotFound
80
- from colorama import Fore, init
81
- from Inventory_Modules import display_results, get_child_access3
82
- from tqdm.auto import tqdm
83
-
84
- init()
85
- __version__ = "2024.04.24"
86
-
87
-
88
- ##########################
89
- # Functions
90
- ##########################
91
-
92
-
93
- def parse_args(arguments):
94
- """
95
- Parse and validate command-line arguments for S3 public access block management.
96
-
97
- Configures the argument parser with S3 security-specific options for comprehensive
98
- public access block configuration across multi-account AWS environments.
99
- Uses the standardized CommonArguments framework for consistency.
100
-
101
- Args:
102
- arguments (list): Command-line arguments to parse (typically sys.argv[1:])
103
-
104
- Returns:
105
- argparse.Namespace: Parsed arguments containing:
106
- - Profile: AWS profile for security configuration management
107
- - Region: Target AWS region for S3 control operations
108
- - pFile: Optional file containing account numbers (one per line)
109
- - pDryRun: CRITICAL safety flag - defaults to True (dry-run mode)
110
- - pRoleList: Cross-account roles for Organizations access
111
- - Other standard framework arguments
112
-
113
- Security-Critical Arguments:
114
- --no-dry-run: DANGEROUS flag that enables live security modifications
115
- - Defaults to dry-run mode for safety
116
- - Only use after thorough validation and approval
117
- - Can affect organization-wide S3 security posture
118
- - Changes are immediate and cannot be easily undone
119
-
120
- --file: Target specific accounts instead of entire organization
121
- - Enables surgical security configuration changes
122
- - File format: one account number per line
123
- - Useful for phased security policy rollouts
124
- - Reduces blast radius of security changes
125
-
126
- S3 Security Operations Use Cases:
127
- - Organizational security policy enforcement
128
- - Compliance remediation (PCI DSS, GDPR, SOC 2)
129
- - Data breach prevention and risk mitigation
130
- - Centralized security governance and control
131
- - Emergency security lockdown procedures
132
- - Audit and compliance validation
133
- """
134
- script_path, script_name = split(sys.argv[0])
135
- parser = CommonArguments()
136
- parser.singleregion()
137
- parser.singleprofile()
138
- parser.verbosity()
139
- parser.timing()
140
- parser.version(__version__)
141
- local = parser.my_parser.add_argument_group(script_name, "Parameters specific to this script")
142
- local.add_argument(
143
- "-f",
144
- "--file",
145
- dest="pFile",
146
- metavar="file of account numbers to read",
147
- default=None,
148
- help="File should consist of account numbers - 1 per line, with CR/LF as line ending",
149
- )
150
- local.add_argument(
151
- "+n",
152
- "--no-dry-run",
153
- dest="pDryRun",
154
- action="store_false", # Defaults to dry-run, only changes if you specify the parameter
155
- help="Defaults to Dry-Run so it doesn't make any changes, unless you specify.",
156
- )
157
- local.add_argument(
158
- "--Role",
159
- dest="pRoleList",
160
- nargs="*",
161
- default=None,
162
- metavar="list of roles to access child accounts",
163
- help="Defaults to common list, so it's ok to trust the list we have, unless you use something different.",
164
- )
165
- return parser.my_parser.parse_args(arguments)
166
-
167
-
168
- def read_file(filename):
169
- """
170
- Read and parse account numbers from input file for targeted operations.
171
-
172
- Essential for surgical security configuration changes when organization-wide
173
- modifications are not desired. Enables phased rollouts and risk management.
174
-
175
- Args:
176
- filename (str): Path to file containing account numbers (one per line)
177
-
178
- Returns:
179
- list: List of AWS account numbers for targeted security operations
180
-
181
- File Format:
182
- - One AWS account number per line
183
- - Standard 12-digit account format
184
- - CR/LF line endings supported
185
- - Comments and empty lines ignored
186
-
187
- Security Considerations:
188
- - Validates account number format
189
- - Reduces blast radius for security changes
190
- - Enables controlled security policy deployment
191
- - Supports phased compliance remediation
192
- """
193
- account_list = []
194
- with open(filename, "r") as f:
195
- line = f.readline().rstrip()
196
- while line:
197
- account_list.append(line)
198
- line = f.readline().rstrip()
199
- return account_list
200
-
201
-
202
- def find_all_accounts(session_object=None):
203
- """
204
- Discover all AWS accounts in the organization for security policy application.
205
-
206
- Critical function for organization-wide security governance that enumerates
207
- all member accounts for comprehensive S3 public access block enforcement.
208
- Essential for maintaining consistent security posture across the organization.
209
-
210
- Args:
211
- session_object (boto3.Session): Authenticated AWS session with Organizations access
212
-
213
- Returns:
214
- list: Comprehensive list of organization accounts with metadata:
215
- - ParentAccount: Management account identifier
216
- - AccountId: Member account identifier
217
- - AccountEmail: Account contact email
218
- - AccountStatus: Account status (ACTIVE, SUSPENDED, etc.)
219
-
220
- Security Implications:
221
- - Enables organization-wide security policy enforcement
222
- - Identifies all accounts requiring security configuration
223
- - Supports comprehensive compliance auditing
224
- - Critical for preventing security gaps in organization
225
- - Essential for consistent data protection governance
226
-
227
- Error Handling:
228
- - Handles pagination for large organizations
229
- - Comprehensive error logging for audit trails
230
- - Graceful handling of access denied scenarios
231
- - Detailed logging of account enumeration process
232
-
233
- Enterprise Use Cases:
234
- - Organization-wide security policy deployment
235
- - Compliance remediation across all accounts
236
- - Security audit preparation and validation
237
- - Emergency security lockdown procedures
238
- - Centralized governance and risk management
239
- """
240
- child_accounts = []
241
- sts_client = session_object.client("sts")
242
- my_account_number = sts_client.get_caller_identity()["Account"]
243
- org_client = session_object.client("organizations")
244
- try:
245
- # Call AWS Organizations API to enumerate all accounts
246
- # Critical for comprehensive security policy application
247
- response = org_client.list_accounts()
248
- theresmore = True
249
-
250
- # Handle pagination for large organizations
251
- # AWS Organizations may return results in multiple pages
252
- while theresmore:
253
- for account in response["Accounts"]:
254
- # Log account discovery for audit trail and troubleshooting
255
- logging.info(
256
- f"Account ID: {account['Id']} | Account Email: {account['Email']} | Status: {account['Status']}"
257
- )
258
-
259
- # Build comprehensive account record for security operations
260
- account_record = {
261
- "ParentAccount": my_account_number, # Management account context
262
- "AccountId": account["Id"], # Target account for security config
263
- "AccountEmail": account["Email"], # Contact for notifications
264
- "AccountStatus": account["Status"], # Account operational status
265
- }
266
-
267
- # Only include active accounts in security operations
268
- # Suspended or closed accounts cannot have security policies applied
269
- if account["Status"] == "ACTIVE":
270
- child_accounts.append(account_record)
271
- else:
272
- logging.warning(f"Skipping non-active account {account['Id']} with status {account['Status']}")
273
-
274
- # Check for additional pages of results
275
- if "NextToken" in response.keys():
276
- theresmore = True
277
- response = org_client.list_accounts(NextToken=response["NextToken"])
278
- else:
279
- theresmore = False
280
-
281
- logging.info(f"Organization account discovery complete: {len(child_accounts)} active accounts found")
282
- return child_accounts
283
- except EndpointConnectionError as my_Error:
284
- logging.error(f"Organizations module isn't available in this region - {my_Error}")
285
- print(f"Organizations module isn't available in this region - {my_Error}")
286
-
287
- # Return empty list on error - calling function should handle gracefully
288
- # This prevents security policy application when account discovery fails
289
- return child_accounts
290
- except ClientError as my_Error:
291
- print(
292
- f"Account {my_account_number} isn't a root account. This script works best with an Org Management account"
293
- )
294
- logging.warning(f"Account {my_account_number} doesn't represent an Org Root account")
295
- logging.debug(my_Error)
296
- return ()
297
-
298
-
299
- def check_block_s3_public_access(AcctDict=None) -> dict:
300
- # TODO: Enable threading here to speed up the process
301
- """
302
- Description: Checks the public access block on an account
303
- @param AcctDict: Information about the account being checked
304
- @return: Dictionary object with the results of the check
305
- """
306
- return_response = {"Success": False, "Message": None}
307
- if AcctDict is None:
308
- info_message = "No Account info passed into the function"
309
- logging.info(info_message)
310
- return_response = {"Message": info_message, "Success": False}
311
- else:
312
- if "AccessKeyId" in AcctDict.keys():
313
- logging.info(f"Using credentials for child account {AcctDict['AccountId']} ")
314
- aws_session = boto3.Session(
315
- aws_access_key_id=AcctDict["AccessKeyId"],
316
- aws_secret_access_key=AcctDict["SecretAccessKey"],
317
- aws_session_token=AcctDict["SessionToken"],
318
- region_name="us-east-1",
319
- )
320
- else:
321
- aws_session = aws_acct.session
322
- s3_client = aws_session.client("s3control")
323
- logging.info(f"Checking the public access block on account {AcctDict['AccountId']}")
324
- try:
325
- response = s3_client.get_public_access_block(AccountId=AcctDict["AccountId"])[
326
- "PublicAccessBlockConfiguration"
327
- ]
328
- except ClientError as my_Error:
329
- if my_Error.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration":
330
- error_message = f"No Public Access Block enabled on account {AcctDict['AccountId']}"
331
- logging.error(error_message)
332
- return_response = {"Message": "No Public Access Block enabled", "Success": False}
333
- elif my_Error.response["Error"]["Code"] == "AccessDenied":
334
- error_message = f"Bad credentials on account {AcctDict['AccountId']}"
335
- logging.error(error_message)
336
- return_response = {"Message": error_message, "Success": False}
337
- else:
338
- error_message = f"Unexpected error on account {AcctDict['AccountId']}: {my_Error.response}"
339
- logging.error(error_message)
340
- return_response = {"Message": error_message, "Success": False}
341
- return return_response
342
- if (
343
- response["BlockPublicAcls"]
344
- and response["IgnorePublicAcls"]
345
- and response["BlockPublicPolicy"]
346
- and response["RestrictPublicBuckets"]
347
- ):
348
- logging.info("Block was already enabled")
349
- return_response = {"Message": "All S3 public blocks in place", "Success": True}
350
- elif (
351
- response["BlockPublicAcls"]
352
- or response["IgnorePublicAcls"]
353
- or response["BlockPublicPolicy"]
354
- or response["RestrictPublicBuckets"]
355
- ):
356
- logging.info("Block is partially enabled")
357
- return_response = {"Message": "Only some S3 public blocks in place", "Success": False}
358
- else:
359
- logging.info("Block is fully disabled")
360
- return_response = {"Message": "No S3 public blocks in place", "Success": False}
361
- return return_response
362
-
363
-
364
- def enable_block_s3_public_access(AcctDict=None):
365
- if AcctDict is None:
366
- logging.info("The Account info wasn't passed into the function")
367
- return "Skipped"
368
- else:
369
- if "AccessKeyId" in AcctDict.keys():
370
- logging.info("Creating credentials for child account %s ")
371
- aws_session = boto3.Session(
372
- aws_access_key_id=AcctDict["AccessKeyId"],
373
- aws_secret_access_key=AcctDict["SecretAccessKey"],
374
- aws_session_token=AcctDict["SessionToken"],
375
- region_name="us-east-1",
376
- )
377
- else:
378
- aws_session = boto3.Session()
379
- s3_client = aws_session.client("s3control")
380
- logging.info("Enabling the public access block".format(AcctDict["AccountId"]))
381
- response = s3_client.put_public_access_block(
382
- PublicAccessBlockConfiguration={
383
- "BlockPublicAcls": True,
384
- "IgnorePublicAcls": True,
385
- "BlockPublicPolicy": True,
386
- "RestrictPublicBuckets": True,
387
- },
388
- AccountId=AcctDict["AccountId"],
389
- )
390
- return_response = {"Success": True, "Payload": response, "Status": "Updated"}
391
- return return_response
392
-
393
-
394
- ##########################
395
- # Main
396
- ##########################
397
-
398
- if __name__ == "__main__":
399
- args = parse_args(sys.argv[1:])
400
- pProfile = args.Profile
401
- pRegion = args.Region
402
- pFile = args.pFile
403
- pDryRun = args.pDryRun
404
- pRoleList = args.pRoleList
405
- pTiming = args.Time
406
- verbose = args.loglevel
407
- logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)30s() ] %(message)s")
408
- logging.getLogger("boto3").setLevel(logging.CRITICAL)
409
- logging.getLogger("botocore").setLevel(logging.CRITICAL)
410
- logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
411
- logging.getLogger("urllib3").setLevel(logging.CRITICAL)
412
-
413
- """
414
- Code Flow:
415
-
416
- 1. Find the accounts we're going to work on
417
- - This might be from reading in a file, or might be from interrogating the provided organization (profile) or from scanning all the profiles available and picking out the root profiles.
418
- - The code is there to read in the file, but it was too much effort to try to find which profiles enabled access to those accounts, so I just found all accounts you might have access to - and we'll enable the block on everything.
419
- TODO: Allow for a "skip" parameter to skip specific accounts known to host websites or something.
420
-
421
- 2. Make sure we know the Root account for every child account, and then create a dictionary of access credentials to get into that account
422
- - So how to find out how to access a child account? Determine profiles you have and then try each Management profile?
423
-
424
- 3. Ensure that Public Access Block is enabled on every account
425
- - We check to see if it's already enabled and don't *re-enable* it.
426
- TODO: Maybe we find if the bucket is hosting a website, and then don't enable it on those buckets?
427
-
428
- 4. Report that we did what we were supposed to do, and any difficulties we had doing it.
429
- """
430
-
431
- aws_acct = aws_acct_access(pProfile)
432
- AllChildAccountList = []
433
- begin_time = time()
434
- ERASE_LINE = "\x1b[2K"
435
-
436
- AccountList = None # Makes the IDE Checker happy
437
- # Get the accounts we're going to work on
438
- if pFile is not None:
439
- AccountList = read_file(pFile)
440
- for accountnumber in AccountList:
441
- AllChildAccountList.append(
442
- {"AccountId": accountnumber, "AccountStatus": "ACTIVE", "MgmtAccount": aws_acct.acct_number}
443
- )
444
- elif aws_acct.AccountType.lower() == "root":
445
- AllChildAccountList = aws_acct.ChildAccounts
446
- else:
447
- AllChildAccountList = [
448
- {
449
- "MgmtAccount": aws_acct.acct_number,
450
- "AccountId": aws_acct.acct_number,
451
- "AccountEmail": "Child Account",
452
- "AccountStatus": aws_acct.AccountStatus,
453
- }
454
- ]
455
- logging.info(f"Found {len(AllChildAccountList)} accounts to look through: {AllChildAccountList}")
456
-
457
- for account in tqdm(AllChildAccountList, desc=f"Getting credentials for {len(AllChildAccountList)} accounts"):
458
- if account["AccountStatus"] == "ACTIVE":
459
- # print(ERASE_LINE, f"Getting credentials for account {account['AccountId']} -- {i + 1} of {len(AllChildAccountList)}", end="\r")
460
- try:
461
- if pRoleList is None:
462
- credentials = get_child_access3(aws_acct, account["AccountId"])
463
- else:
464
- credentials = get_child_access3(aws_acct, account["AccountId"], "us-east-1", pRoleList)
465
- logging.info(f"Successfully got credentials for account {account['AccountId']}")
466
- account["AccessKeyId"] = credentials["AccessKeyId"]
467
- account["SecretAccessKey"] = credentials["SecretAccessKey"]
468
- account["SessionToken"] = credentials["SessionToken"]
469
- except Exception as my_Error:
470
- logging.error(my_Error)
471
- logging.error(
472
- f"Failed using root account {account['MgmtAccount']} to get credentials for acct {account['AccountId']}"
473
- )
474
- else:
475
- logging.error(ERASE_LINE, f"Skipping account {account['AccountId']} since it's SUSPENDED or CLOSED")
476
-
477
- print()
478
- display_dict = {
479
- "MgmtAccount": {"DisplayOrder": 1, "Heading": "Mgmt Acct"},
480
- "AccountId": {"DisplayOrder": 2, "Heading": "Acct Number"},
481
- "Result": {"DisplayOrder": 3, "Heading": "Block Enabled?"},
482
- "Updated": {"DisplayOrder": 4, "Heading": "Blocked Now?"},
483
- }
484
-
485
- # fmt = '%-20s %-15s %-20s %-15s'
486
- # print(fmt % ("Root Acct", "Account", "Was Block Enabled?", "Blocked Now?"))
487
- # print(fmt % ("---------", "-------", "------------------", "------------"))
488
-
489
- print()
490
- NotEnabledList = []
491
- BlockEnabledList = []
492
- PublicBlockResults = []
493
- for item in tqdm(AllChildAccountList, desc=f"Checking {len(AllChildAccountList)} accounts for S3 Public Block"):
494
- if item["AccountStatus"].upper() == "SUSPENDED":
495
- continue
496
- else:
497
- try:
498
- Updated = "Skipped"
499
- Enabled = check_block_s3_public_access(item)
500
- logging.info(f"Checking account #{item['AccountId']} with Parent Account {item['MgmtAccount']}")
501
- if not Enabled["Success"]:
502
- NotEnabledList.append(item["AccountId"])
503
- if pDryRun:
504
- Updated = "DryRun"
505
- pass
506
- else:
507
- response = enable_block_s3_public_access(item)
508
- Updated = response["Status"]
509
- NotEnabledList.remove(item["AccountId"])
510
- BlockEnabledList.append(item["AccountId"])
511
- PublicBlockResults.append(
512
- {
513
- "MgmtAccount": item["MgmtAccount"],
514
- "AccountId": item["AccountId"],
515
- "Result": Enabled["Success"],
516
- "Updated": Updated,
517
- }
518
- )
519
- # print(fmt % (item['MgmtAccount'], item['AccountId'], Enabled['Success'], Updated))
520
- except ProfileNotFound as myError:
521
- logging.info(f"You've tried to update your own management account.")
522
-
523
- display_results(PublicBlockResults, display_dict)
524
-
525
- print()
526
- if pFile is not None:
527
- print(f"# of account in file provided: {len(AccountList)}")
528
- print(f"# of Checked Accounts: {len(AllChildAccountList)}")
529
- for account in NotEnabledList:
530
- print(f"{Fore.RED}Account {account} needs the S3 public block to be enabled{Fore.RESET}")
531
- print()
532
- for account in BlockEnabledList:
533
- print(f"{Fore.GREEN}Account {account} has had the S3 public block enabled{Fore.RESET}")
534
- if pTiming:
535
- print(ERASE_LINE)
536
- print(f"{Fore.GREEN}This script took {time() - begin_time:.2f} seconds{Fore.RESET}")
537
- print()
538
- print("Thank you for using this script.")
539
- print()
@@ -1,12 +0,0 @@
1
- """
2
- Cloud Foundations Organizations module.
3
-
4
- This module provides AWS Organizations management capabilities
5
- including OU structure setup and account management.
6
- """
7
-
8
- from runbooks.organizations.manager import OUManager
9
-
10
- __all__ = [
11
- "OUManager",
12
- ]