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
@@ -0,0 +1,324 @@
1
+ # CloudOps Runbooks: Security Baseline Assessment
2
+
3
+ ## 📖 Overview
4
+
5
+ The **CloudOps Runbooks: Security Baseline Assessment** is a comprehensive tool designed to evaluate the security of AWS environments in accordance with basic security advisories. It provides a structured way to assess your account and workload configurations against **AWS security best practices** and the **AWS Startup Security Baseline (SSB)**. This tool supports **Python (via pip or Docker)** and **AWS Lambda** deployments, offering flexibility for local testing, CI/CD integration, and scalable cloud execution.
6
+
7
+ By automating **15+ critical AWS account security and workload security checks**, this solution empowers startups, enterprises, and DevOps teams to validate their cloud security posture, generate actionable reports, and align with AWS Well-Architected principles.
8
+
9
+ In the **Test Report**, we provide numerous techniques for successfully responding to security threats on AWS with minimal resources. This script is appropriate for usage by early-stage businesses that cannot afford to invest much in security. 
10
+
11
+
12
+ ## ✨ Features: Core Capabilities
13
+
14
+ 1. **Account and Workload Security Checks**:
15
+ - Validates IAM configurations, S3 bucket policies, VPC security groups, and CloudTrail settings.
16
+ 2. **Report Generation**:
17
+ - Generates **multi-language HTML reports** (English, Korean, Japanese).
18
+ 3. **Actionable Insights**:
19
+ - Provides remediation steps for failed checks, mapped to AWS documentation.
20
+ 4. **Flexible Deployment**:
21
+ - Usable as a Python library (pip), containerized application (Docker), or AWS Lambda function.
22
+ 5. **Read-Only Permissions**:
23
+ - Ensures compliance with AWS's **least privilege principle** for non-intrusive diagnostics.
24
+
25
+ ---
26
+
27
+ ## 📂 File Structure
28
+
29
+ This modular structure ensures maintainability and supports seamless integration into pipelines or ad hoc testing.
30
+
31
+ ```plaintext
32
+ src/runbooks/
33
+ ├── security-baseline/
34
+ │ ├── checklist/ # Security check modules
35
+ │ │ ├── iam_password_policy.py # Checks IAM password policy
36
+ │ │ ├── bucket_public_access.py # Validates S3 bucket policies
37
+ │ │ └── ... # More checks for IAM, S3, CloudTrail, etc.
38
+ │ ├── lib/ # Core utilities and constants
39
+ │ │ ├── common.py # Shared helper functions
40
+ │ │ ├── enums.py # Enumerations for reporting
41
+ │ │ ├── language.py # Multi-language support
42
+ │ │ └── permission_list.py # IAM permissions for checks
43
+ │ ├── config.json # Configurable parameters for checks
44
+ │ ├── permission.json # IAM policy for execution
45
+ │ ├── report_generator.py # HTML report generator
46
+ │ ├── run_script.py # Main execution script
47
+ │ └── report_template_en.html # Report templates
48
+ ├── utils/
49
+ │ └── logger.py # Logging utilities
50
+ ```
51
+
52
+ ---
53
+
54
+
55
+ ## 🚀 Deployment and Usage
56
+
57
+ The tool offers multiple deployment options tailored for different use cases, such as local testing, CI/CD pipelines, and cloud-native executions.
58
+
59
+ > TBD: [Watch Video Guide](https://youtu.be/)
60
+
61
+ ### **Option 1: Run Locally with Python**
62
+
63
+ 1. **Clone the Repository**:
64
+ ```bash
65
+ git clone https://github.com/nnthanh101/runbooks.git
66
+ ```
67
+
68
+ 2. Prerequisites: $ `task -d ~ install`
69
+ ```
70
+ echo "Verify the development environment: Python Virtual Environment ..."
71
+ task -d ~ check-tools
72
+ task -d ~ check-aws
73
+ echo "Install Dependencies using uv ..."
74
+ task -d ~ install
75
+ ```
76
+
77
+ 2. **Run the Script**:
78
+ ```bash
79
+ python run_script.py --profile PROFILE_NAME --language EN
80
+ ```
81
+
82
+ ---
83
+
84
+ ### **Option 2: Run with Docker**
85
+
86
+ 1. **Build the Docker Image**:
87
+ ```bash
88
+ docker build -t security-baseline-tester .
89
+ ```
90
+
91
+ 2. **Run the Container**:
92
+ ```bash
93
+ docker run --rm -it -v ~/.aws:/root/.aws:ro security-baseline-tester --profile PROFILE_NAME --language EN
94
+ ```
95
+
96
+ ---
97
+
98
+ ### **Option 3: AWS Lambda Deployment**
99
+
100
+ 1. **Prepare the Lambda Function**:
101
+ - Package the `security-baseline` directory into a ZIP file.
102
+ - Ensure dependencies are included by using tools like **pipenv** or **venv**.
103
+
104
+ 2. **Deploy to AWS Lambda**:
105
+ - Create a Lambda function in the AWS Management Console or using AWS CLI.
106
+ - Attach the `permission.json` IAM policy to the function's execution role.
107
+
108
+ 3. **Invoke the Function**:
109
+ - Use AWS CLI or a scheduled event trigger (e.g., CloudWatch Events).
110
+
111
+ ---
112
+
113
+ ## 🛡️ Security Checks Included
114
+
115
+ The following checks are aligned with the [AWS Startup Security Baseline (SSB)](https://docs.aws.amazon.com/prescriptive-guidance/latest/aws-startup-security-baseline/welcome.html):
116
+
117
+ 1. **Account-Level Security**:
118
+ - Root account MFA enabled
119
+ - No root access keys
120
+ - Alternate contacts configured
121
+
122
+ 2. **IAM Best Practices**:
123
+ - Password policies enforced
124
+ - MFA for IAM users
125
+ - Attached policies preferred over inline policies
126
+
127
+ 3. **Monitoring and Logging**:
128
+ - CloudTrail enabled across all regions
129
+ - GuardDuty activated
130
+ - CloudWatch alarms configured for critical events
131
+
132
+ 4. **S3 Bucket Policies**:
133
+ - Public access block enabled
134
+ - Encryption enforced for bucket objects
135
+
136
+ 5. **VPC and Network Security**:
137
+ - Validates security group configurations
138
+ - Multi-region usage of resources (e.g., EC2 instances, S3 buckets)
139
+
140
+ ---
141
+
142
+ ## 📊 Reports and Insights
143
+
144
+ - **Format**: HTML reports generated in the `results/` directory.
145
+ - **Languages**: Supported in English, Korean, and Japanese.
146
+ - **Insights**:
147
+ - Passed, failed, and skipped checks with detailed descriptions.
148
+ - Direct remediation steps with links to AWS documentation.
149
+
150
+ Sample Report:
151
+
152
+ | Check ID | Description | Result | Remediation Steps |
153
+ |----------|-----------------------------|----------|------------------------------------|
154
+ | 01 | Root account MFA enabled | ✅ Pass | N/A |
155
+ | 02 | CloudTrail enabled | ❌ Fail | [Enable CloudTrail](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-create-and-update-a-trail.html) |
156
+ | 03 | S3 bucket public access | ✅ Pass | N/A |
157
+
158
+ ---
159
+
160
+ ## 📋 Prerequisites
161
+
162
+ ### **IAM Permissions**
163
+
164
+ Attach the policy defined in `permission.json` to the IAM user or role executing the script. This policy ensures **read-only access**, except for specific actions like `iam:GenerateCredentialReport`.
165
+
166
+ ### **AWS CLI Configuration**
167
+ - Set up credentials in the `~/.aws/credentials` file or use AWS CloudShell.
168
+
169
+ ---
170
+
171
+ ## 🔮 Future Enhancements
172
+
173
+ 1. **Multi-Account Scans**:
174
+ - Expand to support AWS Organizations for enterprise-wide checks.
175
+ 2. **AI Integration**:
176
+ - Leverage machine learning for automated anomaly detection and remediation suggestions.
177
+ 3. **Visualization Dashboards**:
178
+ - Integrate with AWS QuickSight or Grafana for real-time security monitoring.
179
+
180
+ ---
181
+
182
+ ## 📢 Feedback and Contributions
183
+
184
+ We value your feedback! Share your ideas or report issues via:
185
+ - **GitHub**: [CloudOps Runbooks Repository](https://github.com/nnthanh101/cloudops-runbooks/issues)
186
+ - **Email**: [support@nnthanh101.com](mailto:support@nnthanh101.com)
187
+
188
+ Let’s work together to make cloud security accessible, effective, and scalable for everyone. 🚀
189
+
190
+ ---
191
+
192
+ ### **Create an IAM User with Permissions**
193
+
194
+ 1. **Navigate to IAM in the AWS Console**:
195
+ - Go to the **IAM service** on the AWS Management Console.
196
+
197
+ 2. **Add a New User**:
198
+ - Select **Users** from the navigation pane, then click **Add users**.
199
+ - Enter a username for the new user under **User name**.
200
+
201
+ 3. **Assign Permissions**:
202
+ - Choose **Attach policies directly** on the **Set permissions** page.
203
+ - Click **Create Policy**, then switch to the **JSON** tab and paste the following policy:
204
+
205
+ ```json
206
+ {
207
+ "Version": "2012-10-17",
208
+ "Statement": [
209
+ {
210
+ "Sid": "SSBUserPermission",
211
+ "Effect": "Allow",
212
+ "Action": [
213
+ "iam:GenerateCredentialReport",
214
+ "s3:GetBucketPublicAccessBlock",
215
+ "iam:GetAccountPasswordPolicy",
216
+ "cloudtrail:GetTrail",
217
+ "ec2:DescribeInstances",
218
+ "guardduty:ListDetectors",
219
+ "cloudtrail:GetTrailStatus",
220
+ "account:GetAlternateContact",
221
+ "ec2:DescribeRegions",
222
+ "s3:ListBucket",
223
+ "iam:ListUserPolicies",
224
+ "support:DescribeTrustedAdvisorChecks",
225
+ "guardduty:GetDetector",
226
+ "cloudtrail:DescribeTrails",
227
+ "s3:GetAccountPublicAccessBlock",
228
+ "s3:ListAllMyBuckets",
229
+ "ec2:DescribeNetworkInterfaces",
230
+ "ec2:DescribeVpcs",
231
+ "iam:ListAttachedUserPolicies",
232
+ "cloudwatch:DescribeAlarms",
233
+ "iam:ListUsers",
234
+ "sts:GetCallerIdentity",
235
+ "iam:GetCredentialReport",
236
+ "ec2:DescribeSubnets"
237
+ ],
238
+ "Resource": "*"
239
+ }
240
+ ]
241
+ }
242
+ ```
243
+
244
+ 4. **Additional Permissions for CloudShell** *(Optional)*:
245
+ - Add the **AWSCloudShellFullAccess** policy if you plan to use AWS CloudShell for assessments.
246
+
247
+ 5. **Complete User Creation**:
248
+ - Attach the policy to the user, then finish user creation by clicking **Next**.
249
+
250
+ 6. **Generate Access Key**:
251
+ - On the user’s **Security credentials** tab, click **Create access key** to generate the key. [Learn more about creating access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey).
252
+
253
+ 7. **Configure AWS CLI**:
254
+ - Set up your AWS credentials by editing the `~/.aws/credentials` file or use AWS CloudShell directly. [AWS CLI configuration guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).
255
+
256
+ ---
257
+
258
+ ### **Run the Script**
259
+
260
+ 1. **Run the Script**:
261
+ ```bash
262
+ python3 run_script.py
263
+ ```
264
+
265
+ 2. **Use Profile or Language Options** *(Optional)*:
266
+ - If you configured AWS CLI with a specific profile, run:
267
+ ```bash
268
+ python3 run_script.py --profile PROFILE_NAME --language EN
269
+ ```
270
+ - Supported languages: **English (EN)**, **Korean (KR)**, **Japanese (JP)**, **Vietnamese (VN)**.
271
+
272
+ 3. **View Results**:
273
+ - Upon completion, an HTML report will be generated in the `results/` directory.
274
+ - If running on AWS CloudShell, download the report locally. [How to download files from AWS CloudShell](https://docs.aws.amazon.com/cloudshell/latest/userguide/getting-started.html#download-file).
275
+
276
+ > ![Sample Report](./images/report_sample_en.png)
277
+
278
+ > ![Sample Report](./images/report_sample_vn.png)
279
+
280
+ ---
281
+
282
+ ## FAQ: Frequently Asked Questions
283
+
284
+ ### **1. How can I test additional security items to enhance AWS account security?**
285
+
286
+ To test a broader range of security configurations, consider using [AWS Trusted Advisor](https://aws.amazon.com/blogs/aws/aws-trusted-advisor-new-priority-capability/).
287
+ This service regularly analyzes your AWS accounts and helps you implement AWS security best practices aligned with the AWS Well-Architected Framework. By managing your security settings through Trusted Advisor, you can systematically improve the security posture of your AWS environment.
288
+
289
+ ---
290
+
291
+ ### **2. Where can I find more information or guidelines to improve AWS security?**
292
+
293
+ AWS provides the [AWS Well-Architected Tool](https://docs.aws.amazon.com/wellarchitected/latest/userguide/intro.html), a comprehensive cloud service for evaluating and optimizing your architecture.
294
+ This tool includes a **Security Pillar**, which outlines detailed best practices for securing your AWS workloads. Use these guidelines to design, assess, and enhance your security strategy effectively.
295
+
296
+ ---
297
+
298
+ ### **3. Can I scan multiple AWS accounts within the same AWS Organization simultaneously?**
299
+
300
+ No, this script currently supports scanning a **single AWS account** at a time.
301
+ To scan additional AWS accounts in the same organization, you must:
302
+ - Create a separate IAM user with the required permissions in each account.
303
+ - Run the script individually for each account.
304
+
305
+ **Note**: Organization-level security settings cannot be assessed using this script. Consider AWS services like **AWS Organizations** for managing policies at scale.
306
+
307
+ ---
308
+
309
+ ### **4. Can I use this script without an IAM Access Key?**
310
+
311
+ Yes, you can run the script without an IAM Access Key by leveraging IAM roles.
312
+ Starting from the **01/Aug/2023**, you can configure and use **IAM Roles** instead of access keys.
313
+
314
+ Follow these steps:
315
+ 1. Refer to [Overview of using IAM roles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-role-overview) to configure a role profile in the AWS CLI.
316
+ 2. Execute the script with the `--profile` option as shown below:
317
+
318
+ ```bash
319
+ python3 run_script.py --profile PROFILE_NAME --language EN
320
+ ```
321
+
322
+ This approach enhances security by reducing the dependency on long-term access keys.
323
+
324
+ ---
@@ -54,7 +54,14 @@ def check_alternate_contact_filling(session, translator) -> common.CheckResult:
54
54
  ret.error_message = f"Unexpected Exception: {str(e)}"
55
55
  logging.error(ret.error_message, exc_info=True)
56
56
  finally:
57
- ret.result_rows.append([contact_type, contact["Name"], contact["EmailAddress"], contact["PhoneNumber"]])
57
+ ret.result_rows.append(
58
+ [
59
+ contact_type,
60
+ contact["Name"],
61
+ contact["EmailAddress"],
62
+ contact["PhoneNumber"],
63
+ ]
64
+ )
58
65
 
59
66
  if ret.level == level.success:
60
67
  ret.msg = translator.translate("success")
@@ -16,7 +16,10 @@ def get_bucket_info(client, bucket_name) -> tuple:
16
16
  if e.response["Error"]["Code"] == "NoSuchPublicAccessBlockConfiguration":
17
17
  return level.danger, [bucket_name, "All Allowed"]
18
18
  else:
19
- logging.error(f"Error getting public access block for bucket {bucket_name}: {str(e)}", exc_info=True)
19
+ logging.error(
20
+ f"Error getting public access block for bucket {bucket_name}: {str(e)}",
21
+ exc_info=True,
22
+ )
20
23
  return level.error, [bucket_name, "ERR"]
21
24
 
22
25
  public_access_block_policy_counter = sum(
@@ -12,7 +12,10 @@ def get_cloudwatch_alarms(client, region):
12
12
  alarms = client.describe_alarms()["MetricAlarms"]
13
13
  return region, alarms
14
14
  except (client.exceptions.InvalidNextToken, botocore.exceptions.ClientError) as e:
15
- logging.error(f"Error getting CloudWatch alarms for region {region}: {str(e)}", exc_info=True)
15
+ logging.error(
16
+ f"Error getting CloudWatch alarms for region {region}: {str(e)}",
17
+ exc_info=True,
18
+ )
16
19
  return region, "ERR"
17
20
 
18
21
 
@@ -37,7 +40,11 @@ def check_cloudwatch_alarm_configuration(session, translator) -> common.CheckRes
37
40
 
38
41
  with ThreadPoolExecutor() as thread_executor:
39
42
  futures = [
40
- thread_executor.submit(get_cloudwatch_alarms, session.client("cloudwatch", region_name=region), region)
43
+ thread_executor.submit(
44
+ get_cloudwatch_alarms,
45
+ session.client("cloudwatch", region_name=region),
46
+ region,
47
+ )
41
48
  for region in regions
42
49
  ]
43
50
 
@@ -16,7 +16,10 @@ def get_guard_duty_configuration(client, region):
16
16
  client.exceptions.InternalServerErrorException,
17
17
  botocore.exceptions.ClientError,
18
18
  ) as e:
19
- logging.error(f"Error getting GuardDuty configuration for region {region}: {str(e)}", exc_info=True)
19
+ logging.error(
20
+ f"Error getting GuardDuty configuration for region {region}: {str(e)}",
21
+ exc_info=True,
22
+ )
20
23
  return region, "ERR"
21
24
 
22
25
 
@@ -41,7 +44,11 @@ def check_guard_duty_enabled(session, translator) -> common.CheckResult:
41
44
 
42
45
  with ThreadPoolExecutor() as executor:
43
46
  futures = [
44
- executor.submit(get_guard_duty_configuration, session.client("guardduty", region_name=region), region)
47
+ executor.submit(
48
+ get_guard_duty_configuration,
49
+ session.client("guardduty", region_name=region),
50
+ region,
51
+ )
45
52
  for region in regions
46
53
  ]
47
54
 
@@ -39,7 +39,11 @@ def check_multiregion_instance_usage(session, translator) -> common.CheckResult:
39
39
 
40
40
  with ThreadPoolExecutor() as executor:
41
41
  futures = [
42
- executor.submit(get_instance_usage_by_region, session.client("ec2", region_name=region), region)
42
+ executor.submit(
43
+ get_instance_usage_by_region,
44
+ session.client("ec2", region_name=region),
45
+ region,
46
+ )
43
47
  for region in regions
44
48
  ]
45
49
 
@@ -29,7 +29,12 @@ def check_access_key(root_credential_report, key_number):
29
29
 
30
30
  if key_active == "TRUE":
31
31
  last_used_days = get_last_used_days(key_last_used)
32
- return f"AccessKey{key_number}", "In Use", format_last_used(last_used_days), True
32
+ return (
33
+ f"AccessKey{key_number}",
34
+ "In Use",
35
+ format_last_used(last_used_days),
36
+ True,
37
+ )
33
38
  return f"AccessKey{key_number}", "Not In Use", "N/A", False
34
39
 
35
40
 
@@ -21,4 +21,4 @@
21
21
  "first_iam_user_row_index": 2,
22
22
  "root_row_index": 1
23
23
  }
24
- }
24
+ }
@@ -21,4 +21,4 @@
21
21
  "first_iam_user_row_index": 2,
22
22
  "root_row_index": 1
23
23
  }
24
- }
24
+ }
@@ -33,4 +33,4 @@
33
33
  "Resource": "*"
34
34
  }
35
35
  ]
36
- }
36
+ }
@@ -52,7 +52,12 @@ class ReportGenerator:
52
52
 
53
53
  ## Attempt to read the template file
54
54
  if not template_path.is_file():
55
- logger.error("Template file '%s' for language '%s' not found at %s", template_filename, lang, template_path)
55
+ logger.error(
56
+ "Template file '%s' for language '%s' not found at %s",
57
+ template_filename,
58
+ lang,
59
+ template_path,
60
+ )
56
61
  raise FileNotFoundError(f"Could not find the template '{template_filename}' for language '{lang}'.")
57
62
 
58
63
  with template_path.open("r", encoding="utf-8") as file:
@@ -131,7 +136,10 @@ class ReportGenerator:
131
136
  formatted_result = {
132
137
  "title": result_dict.get("title", "Unknown"),
133
138
  "message": result_dict.get("msg", "No message"),
134
- "table": self._format_table(result_dict.get("result_cols", []), result_dict.get("result_rows", [])),
139
+ "table": self._format_table(
140
+ result_dict.get("result_cols", []),
141
+ result_dict.get("result_rows", []),
142
+ ),
135
143
  }
136
144
  if level == level_const.error:
137
145
  formatted_result["error_message"] = result_dict.get("error_message", "Unknown error")
@@ -24,19 +24,19 @@
24
24
  </path>
25
25
  </symbol>
26
26
  <symbol id="bi-x-circle-fill" fill="currentColor" viewBox="0 0 16 16">
27
- <path
27
+ <path
28
28
  d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z">
29
29
  </path>
30
30
  </symbol>
31
31
  <symbol id="bi-dash-circle" fill="currentColor" viewBox="0 0 16 16">
32
- <path
32
+ <path
33
33
  d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z">
34
34
  </path>
35
- <path
35
+ <path
36
36
  d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z">
37
37
  </path>
38
38
  </symbol>
39
- </svg>
39
+ </svg>
40
40
 
41
41
  <div class="container">
42
42
  <div class="row justify-content-center">
@@ -49,7 +49,7 @@
49
49
  <div class="col-6">
50
50
  <table class="table">
51
51
  <tr>
52
- <td>Account</td><td>{{ account_id }}</td>
52
+ <td>AWS Account</td><td>{{ account_id }}</td>
53
53
  </tr>
54
54
  <tr>
55
55
  <td>Generated at</td><td>{{ generated_at }}</td>
@@ -88,15 +88,15 @@
88
88
  {% for section in result_sections %}
89
89
  <div class="card-body" id="{{ section.level|lower }}-list">
90
90
  <div class="accordion" id="accordionSection{{ section.level }}">
91
-
91
+
92
92
  {% for item in section.result_items %}
93
93
  <div class="accordion-item">
94
94
  <h2 class="accordion-header" id="panelsStayOpen-heading-{{ section.level|lower }}-{{ '%02d'|format(loop.index) }}">
95
95
  <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}" aria-expanded="true" aria-controls="panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}">
96
96
  <span class="badge text-bg-{% if section.level == 'Error' %}dark{% elif section.level == 'Info' %}primary{% else %}{{ section.level|lower }}{% endif %} rounded-pill">{{ section.level }}</span>
97
- <div class="ms-2 me-auto">{{ item.title }}</div>
97
+ <div class="ms-2 me-auto">{{ item.title }}</div>
98
98
  </button>
99
- </h2>
99
+ </h2>
100
100
  <div id="panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}" class="accordion-collapse collapse" aria-labelledby="panelsStayOpen-heading-{{ section.level|lower }}-{{ '%02d'|format(loop.index) }}">
101
101
  <div class="accordion-body">
102
102
  <div class="alert alert-{% if section.level == 'Error' %}dark{% elif section.level == 'Info' %}primary{% else %}{{ section.level|lower }}{% endif %} d-flex align-items-center" role="alert">
@@ -24,19 +24,19 @@
24
24
  </path>
25
25
  </symbol>
26
26
  <symbol id="bi-x-circle-fill" fill="currentColor" viewBox="0 0 16 16">
27
- <path
27
+ <path
28
28
  d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z">
29
29
  </path>
30
30
  </symbol>
31
31
  <symbol id="bi-dash-circle" fill="currentColor" viewBox="0 0 16 16">
32
- <path
32
+ <path
33
33
  d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z">
34
34
  </path>
35
- <path
35
+ <path
36
36
  d="M4 8a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7A.5.5 0 0 1 4 8z">
37
37
  </path>
38
38
  </symbol>
39
- </svg>
39
+ </svg>
40
40
 
41
41
  <div class="container">
42
42
  <div class="row justify-content-center">
@@ -49,7 +49,7 @@
49
49
  <div class="col-6">
50
50
  <table class="table">
51
51
  <tr>
52
- <td>Account</td><td>{{ account_id }}</td>
52
+ <td>AWS Account</td><td>{{ account_id }}</td>
53
53
  </tr>
54
54
  <tr>
55
55
  <td>Generated at</td><td>{{ generated_at }}</td>
@@ -88,15 +88,15 @@
88
88
  {% for section in result_sections %}
89
89
  <div class="card-body" id="{{ section.level|lower }}-list">
90
90
  <div class="accordion" id="accordionSection{{ section.level }}">
91
-
91
+
92
92
  {% for item in section.result_items %}
93
93
  <div class="accordion-item">
94
94
  <h2 class="accordion-header" id="panelsStayOpen-heading-{{ section.level|lower }}-{{ '%02d'|format(loop.index) }}">
95
95
  <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}" aria-expanded="true" aria-controls="panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}">
96
96
  <span class="badge text-bg-{% if section.level == 'Error' %}dark{% elif section.level == 'Info' %}primary{% else %}{{ section.level|lower }}{% endif %} rounded-pill">{{ section.level }}</span>
97
- <div class="ms-2 me-auto">{{ item.title }}</div>
97
+ <div class="ms-2 me-auto">{{ item.title }}</div>
98
98
  </button>
99
- </h2>
99
+ </h2>
100
100
  <div id="panelsStayOpen-collapse-{{ section.level|lower }}-{{ '%02d'|format(loop.index)}}" class="accordion-collapse collapse" aria-labelledby="panelsStayOpen-heading-{{ section.level|lower }}-{{ '%02d'|format(loop.index) }}">
101
101
  <div class="accordion-body">
102
102
  <div class="alert alert-{% if section.level == 'Error' %}dark{% elif section.level == 'Info' %}primary{% else %}{{ section.level|lower }}{% endif %} d-flex align-items-center" role="alert">