runbooks 0.2.3__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 +8 -8
  199. runbooks/security_baseline/report_template_jp.html +8 -8
  200. runbooks/security_baseline/report_template_kr.html +13 -13
  201. runbooks/security_baseline/report_template_vn.html +8 -8
  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.3.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.3.dist-info/METADATA +0 -435
  219. runbooks-0.2.3.dist-info/RECORD +0 -61
  220. runbooks-0.2.3.dist-info/entry_points.txt +0 -3
  221. runbooks-0.2.3.dist-info/top_level.txt +0 -1
runbooks/base.py ADDED
@@ -0,0 +1,353 @@
1
+ """
2
+ Base classes for Cloud Foundations modules.
3
+
4
+ This module provides common base classes and utilities used across
5
+ all Cloud Foundations components including CFAT, inventory, and organizations.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from datetime import datetime
10
+ from pathlib import Path
11
+ from typing import Any, Dict, List, Optional, Union
12
+
13
+ import boto3
14
+ from botocore.exceptions import BotoCoreError, ClientError
15
+ from loguru import logger
16
+
17
+ try:
18
+ from pydantic import BaseModel
19
+ except ImportError:
20
+ # Fallback BaseModel
21
+ class BaseModel:
22
+ def __init__(self, **kwargs):
23
+ for key, value in kwargs.items():
24
+ setattr(self, key, value)
25
+
26
+ def model_dump(self, exclude_none=True):
27
+ result = {}
28
+ for key, value in self.__dict__.items():
29
+ if not exclude_none or value is not None:
30
+ result[key] = value
31
+ return result
32
+
33
+
34
+ from runbooks.config import RunbooksConfig
35
+ from runbooks.utils import retry_with_backoff
36
+
37
+
38
+ class CloudFoundationsResult(BaseModel):
39
+ """Base result model for Cloud Foundations operations."""
40
+
41
+ timestamp: datetime
42
+ success: bool
43
+ message: str
44
+ data: Optional[Dict[str, Any]] = None
45
+ errors: List[str] = []
46
+
47
+ class Config:
48
+ """Pydantic config."""
49
+
50
+ json_encoders = {datetime: lambda dt: dt.isoformat()}
51
+
52
+
53
+ class CloudFoundationsBase(ABC):
54
+ """
55
+ Abstract base class for Cloud Foundations components.
56
+
57
+ Provides common functionality for AWS operations, error handling,
58
+ session management, and result formatting.
59
+ """
60
+
61
+ def __init__(
62
+ self, profile: Optional[str] = None, region: Optional[str] = None, config: Optional[RunbooksConfig] = None
63
+ ):
64
+ """
65
+ Initialize base Cloud Foundations component.
66
+
67
+ Args:
68
+ profile: AWS profile name
69
+ region: AWS region
70
+ config: Runbooks configuration
71
+ """
72
+ self.config = config or RunbooksConfig()
73
+ self.profile = profile or self.config.aws_profile
74
+ self.region = region or self.config.aws_region
75
+ self._session = None
76
+ self._clients = {}
77
+
78
+ logger.debug(f"Initialized {self.__class__.__name__} with profile: {self.profile}, region: {self.region}")
79
+
80
+ @property
81
+ def session(self) -> boto3.Session:
82
+ """Get or create boto3 session."""
83
+ if self._session is None:
84
+ self._session = self._create_session()
85
+ return self._session
86
+
87
+ def _create_session(self) -> boto3.Session:
88
+ """Create boto3 session with appropriate configuration."""
89
+ session_kwargs = {"profile_name": self.profile}
90
+ if self.region:
91
+ session_kwargs["region_name"] = self.region
92
+
93
+ try:
94
+ session = boto3.Session(**session_kwargs)
95
+ # Test session by getting caller identity
96
+ sts = session.client("sts")
97
+ identity = sts.get_caller_identity()
98
+ logger.debug(f"Session created for account: {identity.get('Account')}")
99
+ return session
100
+ except Exception as e:
101
+ logger.error(f"Failed to create AWS session: {e}")
102
+ raise
103
+
104
+ def get_client(self, service_name: str, region: Optional[str] = None) -> Any:
105
+ """
106
+ Get or create AWS service client with caching.
107
+
108
+ Args:
109
+ service_name: AWS service name (e.g., 'ec2', 's3')
110
+ region: Optional region override
111
+
112
+ Returns:
113
+ Boto3 client for the service
114
+ """
115
+ client_region = region or self.region
116
+ cache_key = f"{service_name}:{client_region}"
117
+
118
+ if cache_key not in self._clients:
119
+ client_kwargs = {}
120
+ if client_region:
121
+ client_kwargs["region_name"] = client_region
122
+
123
+ self._clients[cache_key] = self.session.client(service_name, **client_kwargs)
124
+ logger.debug(f"Created {service_name} client for region: {client_region}")
125
+
126
+ return self._clients[cache_key]
127
+
128
+ def get_resource(self, service_name: str, region: Optional[str] = None) -> Any:
129
+ """
130
+ Get AWS service resource.
131
+
132
+ Args:
133
+ service_name: AWS service name (e.g., 'ec2', 's3')
134
+ region: Optional region override
135
+
136
+ Returns:
137
+ Boto3 resource for the service
138
+ """
139
+ resource_kwargs = {}
140
+ if region or self.region:
141
+ resource_kwargs["region_name"] = region or self.region
142
+
143
+ return self.session.resource(service_name, **resource_kwargs)
144
+
145
+ @retry_with_backoff(max_retries=3, backoff_factor=1.0)
146
+ def _make_aws_call(self, client_method, **kwargs) -> Any:
147
+ """
148
+ Make AWS API call with retry logic.
149
+
150
+ Args:
151
+ client_method: Boto3 client method to call
152
+ **kwargs: Arguments for the method
153
+
154
+ Returns:
155
+ API response
156
+ """
157
+ try:
158
+ return client_method(**kwargs)
159
+ except ClientError as e:
160
+ error_code = e.response["Error"]["Code"]
161
+ error_message = e.response["Error"]["Message"]
162
+ logger.error(f"AWS API error ({error_code}): {error_message}")
163
+ raise
164
+ except BotoCoreError as e:
165
+ logger.error(f"AWS SDK error: {e}")
166
+ raise
167
+
168
+ def get_account_id(self) -> str:
169
+ """Get current AWS account ID."""
170
+ try:
171
+ sts = self.get_client("sts")
172
+ response = self._make_aws_call(sts.get_caller_identity)
173
+ return response["Account"]
174
+ except Exception as e:
175
+ logger.error(f"Failed to get account ID: {e}")
176
+ raise
177
+
178
+ def get_available_regions(self, service_name: str = "ec2") -> List[str]:
179
+ """
180
+ Get list of available AWS regions for a service.
181
+
182
+ Args:
183
+ service_name: AWS service name
184
+
185
+ Returns:
186
+ List of region names
187
+ """
188
+ try:
189
+ client = self.get_client(service_name)
190
+ response = self._make_aws_call(client.describe_regions)
191
+ return [region["RegionName"] for region in response["Regions"]]
192
+ except Exception as e:
193
+ logger.error(f"Failed to get available regions: {e}")
194
+ return []
195
+
196
+ def validate_permissions(self, required_actions: List[str]) -> Dict[str, bool]:
197
+ """
198
+ Validate that current credentials have required permissions.
199
+
200
+ Args:
201
+ required_actions: List of IAM actions to check
202
+
203
+ Returns:
204
+ Dictionary mapping actions to permission status
205
+ """
206
+ results = {}
207
+ iam = self.get_client("iam")
208
+
209
+ for action in required_actions:
210
+ try:
211
+ # Use simulate_principal_policy to check permissions
212
+ response = self._make_aws_call(
213
+ iam.simulate_principal_policy,
214
+ PolicySourceArn=f"arn:aws:iam::{self.get_account_id()}:user/*",
215
+ ActionNames=[action],
216
+ )
217
+
218
+ if response["EvaluationResults"]:
219
+ decision = response["EvaluationResults"][0]["EvalDecision"]
220
+ results[action] = decision == "allowed"
221
+ else:
222
+ results[action] = False
223
+
224
+ except Exception as e:
225
+ logger.warning(f"Could not check permission for {action}: {e}")
226
+ results[action] = False
227
+
228
+ return results
229
+
230
+ @abstractmethod
231
+ def run(self) -> CloudFoundationsResult:
232
+ """
233
+ Run the main operation for this component.
234
+
235
+ Returns:
236
+ Result object with operation status and data
237
+ """
238
+ pass
239
+
240
+ def create_result(
241
+ self, success: bool, message: str, data: Optional[Dict[str, Any]] = None, errors: Optional[List[str]] = None
242
+ ) -> CloudFoundationsResult:
243
+ """
244
+ Create a standardized result object.
245
+
246
+ Args:
247
+ success: Whether operation succeeded
248
+ message: Result message
249
+ data: Optional result data
250
+ errors: Optional list of errors
251
+
252
+ Returns:
253
+ CloudFoundationsResult object
254
+ """
255
+ return CloudFoundationsResult(
256
+ timestamp=datetime.now(), success=success, message=message, data=data or {}, errors=errors or []
257
+ )
258
+
259
+
260
+ class CloudFoundationsFormatter:
261
+ """Base formatter for Cloud Foundations output."""
262
+
263
+ def __init__(self, data: Any):
264
+ """Initialize formatter with data."""
265
+ self.data = data
266
+
267
+ def to_dict(self) -> Dict[str, Any]:
268
+ """Convert data to dictionary format."""
269
+ if hasattr(self.data, "model_dump"):
270
+ return self.data.model_dump()
271
+ elif hasattr(self.data, "dict"):
272
+ return self.data.dict()
273
+ else:
274
+ return {"data": self.data}
275
+
276
+ def to_json(self, file_path: Union[str, Path]) -> None:
277
+ """Save data as JSON file."""
278
+ import json
279
+
280
+ output_path = Path(file_path)
281
+ output_path.parent.mkdir(parents=True, exist_ok=True)
282
+
283
+ with open(output_path, "w", encoding="utf-8") as f:
284
+ json.dump(self.to_dict(), f, indent=2, default=str)
285
+
286
+ logger.info(f"JSON output saved to: {output_path}")
287
+
288
+ def to_csv(self, file_path: Union[str, Path]) -> None:
289
+ """Save data as CSV file."""
290
+ try:
291
+ import pandas as pd
292
+ except ImportError:
293
+ logger.error("pandas is required for CSV export. Install with: pip install pandas")
294
+ return
295
+
296
+ output_path = Path(file_path)
297
+ output_path.parent.mkdir(parents=True, exist_ok=True)
298
+
299
+ # Convert to DataFrame
300
+ if isinstance(self.data, list):
301
+ df = pd.DataFrame(self.data)
302
+ else:
303
+ df = pd.DataFrame([self.to_dict()])
304
+
305
+ df.to_csv(output_path, index=False)
306
+ logger.info(f"CSV output saved to: {output_path}")
307
+
308
+ def to_excel(self, file_path: Union[str, Path]) -> None:
309
+ """Save data as Excel file."""
310
+ try:
311
+ import pandas as pd
312
+ except ImportError:
313
+ logger.error("pandas is required for Excel export. Install with: pip install pandas")
314
+ return
315
+
316
+ output_path = Path(file_path)
317
+ output_path.parent.mkdir(parents=True, exist_ok=True)
318
+
319
+ # Convert to DataFrame
320
+ if isinstance(self.data, list):
321
+ df = pd.DataFrame(self.data)
322
+ else:
323
+ df = pd.DataFrame([self.to_dict()])
324
+
325
+ df.to_excel(output_path, index=False)
326
+ logger.info(f"Excel output saved to: {output_path}")
327
+
328
+
329
+ class ProgressTracker:
330
+ """Simple progress tracking for long-running operations."""
331
+
332
+ def __init__(self, total: int, description: str = "Processing"):
333
+ """Initialize progress tracker."""
334
+ self.total = total
335
+ self.current = 0
336
+ self.description = description
337
+ self.start_time = datetime.now()
338
+
339
+ def update(self, increment: int = 1, status: Optional[str] = None) -> None:
340
+ """Update progress."""
341
+ self.current += increment
342
+ percentage = (self.current / self.total) * 100 if self.total > 0 else 0
343
+
344
+ elapsed = datetime.now() - self.start_time
345
+
346
+ status_msg = f" - {status}" if status else ""
347
+ logger.info(f"{self.description}: {self.current}/{self.total} ({percentage:.1f}%){status_msg}")
348
+
349
+ def complete(self, message: Optional[str] = None) -> None:
350
+ """Mark progress as complete."""
351
+ elapsed = datetime.now() - self.start_time
352
+ final_msg = message or f"{self.description} completed"
353
+ logger.info(f"{final_msg} in {elapsed.total_seconds():.1f}s")
@@ -0,0 +1,49 @@
1
+ # Cloud Foundation Assessment Tool (CFAT)
2
+
3
+ CFAT is an open-source solution designed to provide automated discovery of an AWS environment and its multi-account architecture. Additionally, CFAT will review the environment, checking for common configurations and best practices for your AWS Organization. The tool will produce a backlog of tasks to complete, along with remediation guidance. CFAT is simple to execute, requiring only that it be executed within the AWS Management Account in the AWS CloudShell.
4
+
5
+ >**Note:** CFAT can operate with `READONLY` permissions **plus CloudShell permissions** to the AWS account, and does not make any changes to the AWS environment. All information generated from the tool is outputted to your local AWS CloudShell environment.
6
+
7
+ ## How to Use
8
+
9
+ 1. Go into an AWS account which is a `Management Account` and open CloudShell terminal.
10
+ ![Find CloudShell](./docs/open-cloudshell.png)
11
+ 2. Ensure you have right now admin permissions or the proper *READONLY* permissions that include ability to use AWS CloudShell
12
+ * For least privilege readonly, leverage the IAM Managed Policies:
13
+ - `arn:aws:iam::aws:policy/ReadOnlyAccess`
14
+ - `arn:aws:iam::aws:policy/AWSCloudShellFullAccess`
15
+ 3. Within AWS CloudShell the following command: `curl -sSL https://raw.githubusercontent.com/cloud-foundations-on-aws/cloud-foundations-templates/main/cfat/run-assessment.sh | sh`
16
+ ![Run CloudShell](./docs/cloudshell-console-run.png)
17
+ 4. Watch screen scroll through output looking for any errors.
18
+ <br/><img src="./docs/cloudshell-output.png" alt="drawing" width="50%" height="50%"/>
19
+ 5. Once done you will see the tool created a directory called ./cfat
20
+ * verify by running `ls` in the current working directory you are in
21
+ 6. The CFAT creates a zip archive containing several artifacts (see [Generated Documentation and Artifacts](#generated-documentation-and-artifacts))
22
+ 7. Within the CloudShell window, go to top right of the page and click on `Actions` button and click on `Download File`
23
+ <br/><img src="./docs/cloudshell-download.png" alt="drawing" width="30%" height="30%"/>
24
+ 8. In the download file enter `./cfat/assessment.zip`
25
+ <br/><img src="./docs/downloadfile.png" alt="drawing" width="50%" height="50%"/>
26
+ 9. File is download which you can unzip and view the generated documentation and artifacts.
27
+
28
+ ## Generated Documentation and Artifacts
29
+
30
+ Running the CFAT produces an archive assessments folder `./cfat/assessment.zip` in the current working directory you run the program from. Unzipping the archive will enable you to access 4 files which were generated during the assessment:
31
+
32
+ 1. **cfat.txt** - file contains a detailed text report of the assessment. Use this file to determine work needed to be completed. An example of a generated report can be found at [./docs/cfat.txt](./docs/cfat.txt). As illustrated below, the header in the report will give you a quick status and an estimated level of effort (loe) to complete the requirements.
33
+ ![report header](./docs/report-header.png)
34
+ 2. **cfat-checks.csv** - output file of the table result which is located in the detailed report (cfat.txt). The csv output is to let you organize and sort the findings. An example of a generated report can be found at [./docs/cfat-checks.csv](./docs/cfat-checks.csv)
35
+ ![check output](./docs/checks-output.png)
36
+ 3. **asana-import.csv** - all tasks created in a csv file format that allow you to easily import the items into your Asana managed backlog. An example of a generated import can be found at [./docs/asana-import.csv](./docs/asana-import.csv)
37
+ 4. **jira-import.csv** - all tasks created in a csv file format that allow you to easily import the items into your Jira managed backlog. An example of a generated import can be found at[./docs/jira-import.csv](./docs/jira-import.csv)
38
+
39
+ ## Features
40
+
41
+ * **Automated Discovery:** CFAT automates the discovery process, minimizing the need for manual checks and providing a quick overview of the environment.
42
+ * **READONLY Access:** The tool operates with READONLY access (**plus CloudShell permissions**) to the AWS account, ensuring that it does not make any modifications or interfere with the existing setup.
43
+ * **Importable Backlog:** The tool creates common project management software importable file allowing you to import CFAT findings into services like Jira and Asana.
44
+ * **AWS CloudShell Compatibility:** CFAT is designed to be executed within AWS CloudShell, providing a convenient and secure environment for running discovery.
45
+ * **Developed in JavaScript and AWS-SDK v3:** CFAT is implemented using JavaScript and relies on the latest AWS-SDK v3 for seamless interaction with AWS services.
46
+
47
+ ## Security Considerations
48
+
49
+ * The tool is designed to operate with `READONLY` access (**plus permissions to run CloudShell**), minimizing the risk of unintended changes to your environment. All data is outputted into your local CloudShell environment.
@@ -0,0 +1,74 @@
1
+ """
2
+ Cloud Foundations Assessment Tool (CFAT) - Enterprise CloudOps Assessment.
3
+
4
+ This module provides comprehensive AWS account assessment capabilities
5
+ following Cloud Foundations best practices with enterprise-grade
6
+ features including:
7
+
8
+ - Multi-format reporting (HTML, CSV, JSON, Markdown)
9
+ - Parallel assessment execution
10
+ - Customizable check configurations
11
+ - Compliance framework alignment
12
+ - Advanced scoring and risk analysis
13
+
14
+ The CFAT module is designed for DevOps and SRE teams to automate
15
+ compliance validation, security assessment, and operational
16
+ readiness evaluation across AWS environments.
17
+
18
+ Example:
19
+ ```python
20
+ from runbooks.cfat import AssessmentRunner, Severity
21
+
22
+ # Initialize and configure assessment
23
+ runner = AssessmentRunner(profile="prod", region="us-east-1")
24
+ runner.set_min_severity(Severity.WARNING)
25
+
26
+ # Run assessment
27
+ report = runner.run_assessment()
28
+
29
+ # Export results
30
+ report.to_html("assessment_report.html")
31
+ report.to_json("findings.json")
32
+
33
+ print(f"Compliance Score: {report.summary.compliance_score}/100")
34
+ print(f"Critical Issues: {report.summary.critical_issues}")
35
+ ```
36
+
37
+ Version: 0.5.0 (Enhanced with enterprise features)
38
+ """
39
+
40
+ # Core assessment engine
41
+ # Enhanced data models
42
+ from runbooks.cfat.models import (
43
+ AssessmentConfig,
44
+ # Core models
45
+ AssessmentReport,
46
+ AssessmentResult,
47
+ AssessmentSummary,
48
+ CheckConfig,
49
+ CheckStatus,
50
+ # Enums
51
+ Severity,
52
+ )
53
+ from runbooks.cfat.runner import AssessmentRunner
54
+
55
+ # Version info
56
+ __version__ = "0.5.0"
57
+ __author__ = "CloudOps Runbooks Team"
58
+
59
+ # Public API exports
60
+ __all__ = [
61
+ # Core functionality
62
+ "AssessmentRunner",
63
+ # Data models
64
+ "AssessmentReport",
65
+ "AssessmentResult",
66
+ "AssessmentSummary",
67
+ "AssessmentConfig",
68
+ "CheckConfig",
69
+ # Enums
70
+ "Severity",
71
+ "CheckStatus",
72
+ # Metadata
73
+ "__version__",
74
+ ]