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,294 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- import logging
4
- import sys
5
- from os.path import split
6
- from queue import Queue
7
- from threading import Thread
8
- from time import time
9
-
10
- from ArgumentsClass import CommonArguments
11
- from botocore.exceptions import ClientError
12
- from colorama import Fore, init
13
- from Inventory_Modules import display_results, find_cw_groups_retention2, get_all_credentials
14
- from tqdm.auto import tqdm
15
-
16
- init()
17
- __version__ = "2024.05.10"
18
- ERASE_LINE = "\x1b[2K"
19
- begin_time = time()
20
-
21
-
22
- ##################
23
- # Functions
24
- ##################
25
- def parse_args(f_arguments):
26
- script_path, script_name = split(sys.argv[0])
27
- parser = CommonArguments()
28
- parser.multiprofile()
29
- parser.multiregion()
30
- parser.extendedargs()
31
- parser.rootOnly()
32
- parser.rolestouse()
33
- parser.save_to_file()
34
- parser.verbosity()
35
- parser.timing()
36
- parser.version(__version__)
37
- local = parser.my_parser.add_argument_group(script_name, "Parameters specific to this script")
38
-
39
- local.add_argument(
40
- "+R",
41
- "--ReplaceRetention",
42
- help="The retention you want to update to on all groups that match.",
43
- default=None,
44
- metavar="retention days",
45
- type=int,
46
- choices=[0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, 3653],
47
- dest="pRetentionDays",
48
- )
49
- local.add_argument(
50
- "-o",
51
- "--OldRetention",
52
- help="The retention you want to change on all groups that match. Use '0' for 'Never'",
53
- default=None,
54
- metavar="retention days",
55
- type=int,
56
- choices=[0, 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 2192, 2557, 2922, 3288, 3653],
57
- dest="pOldRetentionDays",
58
- )
59
- return parser.my_parser.parse_args(f_arguments)
60
-
61
-
62
- def check_cw_groups_retention(f_all_credential_list: list) -> list:
63
- """
64
- This function will check the retention on all CW Groups in all accounts.
65
- @param f_all_credential_list: Listing of all credentials for accounts we'll look into
66
- @return: Returns a list of all CW Groups in all accounts provided by the credentials submitted.
67
- """
68
-
69
- class FindCWGroups(Thread):
70
- def __init__(self, queue):
71
- Thread.__init__(self)
72
- self.queue = queue
73
-
74
- def run(self):
75
- while True:
76
- # Get the work from the queue and expand the tuple
77
- c_account_credentials = self.queue.get()
78
- pbar.update()
79
- logging.info(f"De-queued info for account number {c_account_credentials['AccountId']}")
80
- try:
81
- CW_Groups = find_cw_groups_retention2(c_account_credentials)
82
- if len(CW_Groups) > 0:
83
- for logGroup in CW_Groups:
84
- if "retentionInDays" in logGroup.keys():
85
- logGroup["Retention"] = logGroup["retentionInDays"]
86
- else:
87
- logGroup["Retention"] = "Never"
88
- logGroup["Name"] = logGroup["logGroupName"]
89
- logGroup["Size"] = logGroup["storedBytes"]
90
- logGroup["AccessKeyId"] = c_account_credentials["AccessKeyId"]
91
- logGroup["SecretAccessKey"] = c_account_credentials["SecretAccessKey"]
92
- logGroup["SessionToken"] = c_account_credentials["SessionToken"]
93
- logGroup["ParentProfile"] = (
94
- c_account_credentials["Profile"]
95
- if c_account_credentials["Profile"] is not None
96
- else "default"
97
- )
98
- logGroup["MgmtAccount"] = c_account_credentials["MgmtAccount"]
99
- logGroup["AccountId"] = c_account_credentials["AccountId"]
100
- logGroup["Region"] = c_account_credentials["Region"]
101
- AllCWLogGroups.extend(CW_Groups)
102
-
103
- except KeyError as my_Error:
104
- logging.error(f"Account Access failed - trying to access {c_account_credentials['AccountId']}")
105
- logging.info(f"Actual Error: {my_Error}")
106
- pass
107
- except AttributeError as my_Error:
108
- logging.error(f"Error: Likely that one of the supplied profiles was wrong")
109
- logging.warning(my_Error)
110
- continue
111
- except ClientError as my_Error:
112
- if "AuthFailure" in str(my_Error):
113
- logging.error(
114
- f"Authorization Failure accessing account {c_account_credentials['AccountId']} in {c_account_credentials['Region']} region"
115
- )
116
- logging.warning(
117
- f"It's possible that the region {c_account_credentials['Region']} hasn't been opted-into"
118
- )
119
- continue
120
- else:
121
- logging.error(f"Error: Likely throttling errors from too much activity")
122
- logging.warning(my_Error)
123
- continue
124
- finally:
125
- self.queue.task_done()
126
-
127
- checkqueue = Queue()
128
-
129
- AllCWLogGroups = []
130
- WorkerThreads = min(len(f_all_credential_list), 25)
131
- WorkerThreads = min(len(f_all_credential_list), 1)
132
-
133
- pbar = tqdm(
134
- desc=f"Finding CloudWatch log groups from {len(f_all_credential_list)} accounts / regions",
135
- total=len(f_all_credential_list),
136
- unit=" locations",
137
- )
138
-
139
- for x in range(WorkerThreads):
140
- worker = FindCWGroups(checkqueue)
141
- # Setting daemon to True will let the main thread exit even though the workers are blocking
142
- worker.daemon = True
143
- worker.start()
144
-
145
- for credential in f_all_credential_list:
146
- logging.info(f"Beginning to queue data - starting with {credential['AccountId']}")
147
- try:
148
- # While double parens are necessary below, if you're queuing multiple values, we're only queuing one right now.
149
- # But if/ when we add fragment finding, I'm leaving this comment here to remind myself of that.
150
- # checkqueue.put((credential))
151
- checkqueue.put(credential)
152
- except ClientError as my_Error:
153
- if "AuthFailure" in str(my_Error):
154
- logging.error(
155
- f"Authorization Failure accessing account {credential['AccountId']} in {credential['Region']} region"
156
- )
157
- logging.warning(f"It's possible that the region {credential['Region']} hasn't been opted-into")
158
- pass
159
- checkqueue.join()
160
- pbar.close()
161
- return AllCWLogGroups
162
-
163
-
164
- def update_cw_groups_retention(fCWGroups: list, fOldRetentionDays: int = None, fRetentionDays: int = None):
165
- import boto3
166
-
167
- if fOldRetentionDays is None:
168
- fOldRetentionDays = 0
169
- Success = True
170
- for item in fCWGroups:
171
- cw_session = boto3.Session(
172
- aws_access_key_id=item["AccessKeyId"],
173
- aws_secret_access_key=item["SecretAccessKey"],
174
- aws_session_token=item["SessionToken"],
175
- region_name=item["Region"],
176
- )
177
- cw_client = cw_session.client("logs")
178
- logging.info(f"Connecting to account {item['AccountId']}")
179
- try:
180
- print(
181
- f"{ERASE_LINE}Updating log group {item['logGroupName']} account {item['AccountId']} in region {item['Region']}",
182
- end="\r",
183
- )
184
- if "retentionInDays" not in item.keys():
185
- retentionPeriod = "Never"
186
- else:
187
- retentionPeriod = item["retentionInDays"]
188
- if (
189
- fOldRetentionDays == 0 and "retentionInDays" not in item.keys()
190
- ) or retentionPeriod == fOldRetentionDays:
191
- result = cw_client.put_retention_policy(
192
- logGroupName=item["logGroupName"], retentionInDays=fRetentionDays
193
- )
194
- print(
195
- f"Account: {item['AccountId']} in Region: {item['Region']} updated {item['logGroupName']} from {retentionPeriod} to {fRetentionDays} days"
196
- )
197
- Updated = True
198
- else:
199
- Updated = False
200
- logging.info(
201
- f"Skipped {item['logGroupName']} in account: {item['AccountId']} in Region: {item['Region']} as it didn't match criteria"
202
- )
203
- Success = True
204
- except ClientError as my_Error:
205
- logging.error(my_Error)
206
- Success = False
207
- return Success
208
- return Success
209
-
210
-
211
- ##################
212
- # Main
213
- ##################
214
-
215
- if __name__ == "__main__":
216
- args = parse_args(sys.argv[1:])
217
-
218
- pProfiles = args.Profiles
219
- pRegionList = args.Regions
220
- pAccounts = args.Accounts
221
- pSkipAccounts = args.SkipAccounts
222
- pSkipProfiles = args.SkipProfiles
223
- pAccessRoles = args.AccessRoles
224
- pRetentionDays = args.pRetentionDays
225
- pOldRetentionDays = args.pOldRetentionDays
226
- pRootOnly = args.RootOnly
227
- pFilename = args.Filename
228
- pTiming = args.Time
229
- verbose = args.loglevel
230
- logging.basicConfig(level=verbose, format="[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s")
231
- logging.getLogger("boto3").setLevel(logging.CRITICAL)
232
- logging.getLogger("botocore").setLevel(logging.CRITICAL)
233
- logging.getLogger("s3transfer").setLevel(logging.CRITICAL)
234
- logging.getLogger("urllib3").setLevel(logging.CRITICAL)
235
-
236
- print()
237
- print(f"Checking for CW Log Groups... ")
238
- print()
239
-
240
- CredentialList = get_all_credentials(
241
- pProfiles, pTiming, pSkipProfiles, pSkipAccounts, pRootOnly, pAccounts, pRegionList, pAccessRoles
242
- )
243
- SuccessfulAccountAccesses = [x for x in CredentialList if x["Success"]]
244
- AllChildAccounts = list(set([(x["MgmtAccount"], x["AccountId"]) for x in SuccessfulAccountAccesses]))
245
- RegionList = list(set([x["Region"] for x in SuccessfulAccountAccesses]))
246
-
247
- display_dict = {
248
- # 'ParentProfile': {'DisplayOrder': 1, 'Heading': 'Parent Profile'},
249
- "MgmtAccount": {"DisplayOrder": 2, "Heading": "Mgmt Acct"},
250
- "AccountId": {"DisplayOrder": 3, "Heading": "Acct Number"},
251
- "Region": {"DisplayOrder": 4, "Heading": "Region"},
252
- "Retention": {"DisplayOrder": 5, "Heading": "Days Retention", "Condition": ["Never"]},
253
- "Name": {"DisplayOrder": 7, "Heading": "CW Log Name"},
254
- "Size": {"DisplayOrder": 6, "Heading": "Size (Bytes)"},
255
- }
256
-
257
- CWGroups = check_cw_groups_retention(CredentialList)
258
- sorted_CWGroups = sorted(CWGroups, key=lambda k: (k["MgmtAccount"], k["AccountId"], k["Region"], k["Name"]))
259
-
260
- display_results(sorted_CWGroups, display_dict, None, pFilename)
261
-
262
- print(ERASE_LINE)
263
- totalspace = 0
264
- for i in CWGroups:
265
- totalspace += i["storedBytes"]
266
- print(
267
- f"Found {len(CWGroups)} log groups across {len(AllChildAccounts)} accounts across {len(RegionList)} regions, representing {totalspace / 1024 / 1024 / 1024:,.3f} GB"
268
- )
269
- print(f"To give you a small idea - in us-east-1 - it costs $0.03 per GB per month to store (after 5GB).")
270
- if totalspace / 1024 / 1024 / 1024 <= 5.0:
271
- print("Which means this is essentially free for you...")
272
- else:
273
- print(
274
- f"This means you're paying about ${((totalspace / 1024 / 1024 / 1024) - 5) * 0.03:,.2f} per month in CW storage charges"
275
- )
276
-
277
- if pRetentionDays is not None:
278
- print(f"As per your request - updating ALL retention periods to {pRetentionDays} days")
279
- print(f"")
280
- UpdateAllRetention = input(
281
- f"This is definitely an intrusive command, so please confirm you want to do this (y/n): "
282
- ) in ["Y", "y"]
283
- if UpdateAllRetention:
284
- print(f"Updating all log groups to have a {pRetentionDays} retention period")
285
- update_cw_groups_retention(CWGroups, pOldRetentionDays, pRetentionDays)
286
- else:
287
- print(f"No changes made")
288
- print()
289
- if pTiming:
290
- print(ERASE_LINE)
291
- print(f"{Fore.GREEN}This script took {time() - begin_time:.2f} seconds{Fore.RESET}")
292
- print()
293
- print("Thank you for using this script")
294
- print()