cloudsplaining 0.6.3__tar.gz → 0.8.0__tar.gz

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 (129) hide show
  1. cloudsplaining-0.8.0/LICENSE +12 -0
  2. cloudsplaining-0.8.0/PKG-INFO +416 -0
  3. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/README.md +2 -2
  4. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/__init__.py +10 -11
  5. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/bin/cli.py +3 -1
  6. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/bin/version.py +1 -1
  7. cloudsplaining-0.8.0/cloudsplaining/command/__init__.py +11 -0
  8. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/create_exclusions_file.py +15 -7
  9. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/create_multi_account_config_file.py +17 -10
  10. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/download.py +33 -22
  11. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/expand_policy.py +12 -5
  12. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/scan.py +122 -59
  13. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/scan_multi_account.py +121 -79
  14. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/command/scan_policy_file.py +54 -84
  15. cloudsplaining-0.8.0/cloudsplaining/output/dist/js/index.js +63 -0
  16. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/policy_finding.py +48 -49
  17. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/report.py +17 -12
  18. cloudsplaining-0.8.0/cloudsplaining/output/src/components/Summary.vue +167 -0
  19. cloudsplaining-0.8.0/cloudsplaining/output/src/components/charts/SummaryFindings.vue +124 -0
  20. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/assume_role_policy_document.py +7 -8
  21. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/authorization_details.py +17 -25
  22. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/group_details.py +44 -61
  23. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/inline_policy.py +83 -92
  24. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/managed_policy_detail.py +100 -122
  25. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/policy_document.py +58 -85
  26. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/resource_policy_document.py +9 -20
  27. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/role_details.py +49 -66
  28. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/statement_detail.py +49 -76
  29. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/user_details.py +46 -63
  30. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/aws_login.py +14 -21
  31. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/constants.py +6 -5
  32. cloudsplaining-0.8.0/cloudsplaining/shared/exceptions.py +2 -0
  33. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/exclusions.py +26 -25
  34. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/utils.py +19 -27
  35. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/validation.py +9 -8
  36. cloudsplaining-0.8.0/cloudsplaining.egg-info/PKG-INFO +416 -0
  37. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/SOURCES.txt +2 -1
  38. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/requires.txt +1 -1
  39. cloudsplaining-0.8.0/pyproject.toml +82 -0
  40. cloudsplaining-0.8.0/setup.cfg +4 -0
  41. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/setup.py +30 -43
  42. cloudsplaining-0.6.3/PKG-INFO +0 -414
  43. cloudsplaining-0.6.3/cloudsplaining/command/__init__.py +0 -8
  44. cloudsplaining-0.6.3/cloudsplaining/output/dist/js/index.js +0 -334
  45. cloudsplaining-0.6.3/cloudsplaining/output/src/components/Summary.vue +0 -164
  46. cloudsplaining-0.6.3/cloudsplaining/output/src/components/charts/SummaryFindings.vue +0 -108
  47. cloudsplaining-0.6.3/cloudsplaining/shared/exceptions.py +0 -3
  48. cloudsplaining-0.6.3/cloudsplaining.egg-info/PKG-INFO +0 -414
  49. cloudsplaining-0.6.3/setup.cfg +0 -38
  50. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/MANIFEST.in +0 -0
  51. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/bin/__init__.py +0 -0
  52. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/__init__.py +0 -0
  53. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/dist/index.html +0 -0
  54. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/dist/js/chunk-vendors.js +0 -0
  55. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/public/index.html +0 -0
  56. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/App.vue +0 -0
  57. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/1-overview.md +0 -0
  58. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/2-triage-guidance.md +0 -0
  59. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/3-remediation-guidance.md +0 -0
  60. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/4-validation.md +0 -0
  61. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-assumable-by-compute-service.md +0 -0
  62. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-credentials-exposure.md +0 -0
  63. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-data-exfiltration.md +0 -0
  64. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-infrastructure-modification.md +0 -0
  65. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-privilege-escalation.md +0 -0
  66. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-resource-exposure.md +0 -0
  67. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/definition-service-wildcard.md +0 -0
  68. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/glossary.md +0 -0
  69. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/how-do-i-validate-results.md +0 -0
  70. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/identifying-false-positives.md +0 -0
  71. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/logo.png +0 -0
  72. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/summary.md +0 -0
  73. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/assets/what-should-i-do.md +0 -0
  74. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/Appendix.vue +0 -0
  75. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/Button.vue +0 -0
  76. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/Glossary.vue +0 -0
  77. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/Guidance.vue +0 -0
  78. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/InlinePolicies.vue +0 -0
  79. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/LinkToFinding.vue +0 -0
  80. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/ManagedPolicies.vue +0 -0
  81. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/PolicyTable.vue +0 -0
  82. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/Principals.vue +0 -0
  83. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/ReportMetadata.vue +0 -0
  84. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/TaskTable.vue +0 -0
  85. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/AssumeRoleDetails.vue +0 -0
  86. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/FindingCard.vue +0 -0
  87. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/FindingDetails.vue +0 -0
  88. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/PolicyDocumentDetails.vue +0 -0
  89. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/PrivilegeEscalationDetails.vue +0 -0
  90. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/PrivilegeEscalationFormat.vue +0 -0
  91. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/RiskAlertIndicators.vue +0 -0
  92. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/finding/StandardRiskDetails.vue +0 -0
  93. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/principals/PrincipalMetadata.vue +0 -0
  94. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/components/principals/RisksPerPrincipal.vue +0 -0
  95. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/main.js +0 -0
  96. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/routes/routes.js +0 -0
  97. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/sampleData.js +0 -0
  98. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/groups-test.js +0 -0
  99. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/inline-policies-test.js +0 -0
  100. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/managed-policies-test.js +0 -0
  101. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/other-test.js +0 -0
  102. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/principals-test.js +0 -0
  103. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/roles-test.js +0 -0
  104. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/test/task-table-test.js +0 -0
  105. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/glossary.js +0 -0
  106. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/groups.js +0 -0
  107. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/inline-policies.js +0 -0
  108. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/managed-policies.js +0 -0
  109. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/other.js +0 -0
  110. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/principals.js +0 -0
  111. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/roles.js +0 -0
  112. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/util/task-table.js +0 -0
  113. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/Appendices.vue +0 -0
  114. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/AwsPolicies.vue +0 -0
  115. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/CustomerPolicies.vue +0 -0
  116. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/Guidance.vue +0 -0
  117. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/IamPrincipals.vue +0 -0
  118. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/InlinePolicies.vue +0 -0
  119. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/src/views/Summary.vue +0 -0
  120. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/output/template.html +0 -0
  121. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/py.typed +0 -0
  122. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/scan/__init__.py +0 -0
  123. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/__init__.py +0 -0
  124. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/default-exclusions.yml +0 -0
  125. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining/shared/multi-account-config.yml +0 -0
  126. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/dependency_links.txt +0 -0
  127. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/entry_points.txt +0 -0
  128. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/top_level.txt +0 -0
  129. {cloudsplaining-0.6.3 → cloudsplaining-0.8.0}/cloudsplaining.egg-info/zip-safe +0 -0
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2020, Salesforce.com, Inc.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+
10
+ * Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,416 @@
1
+ Metadata-Version: 2.1
2
+ Name: cloudsplaining
3
+ Version: 0.8.0
4
+ Summary: AWS IAM Security Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report.
5
+ Home-page: https://github.com/salesforce/cloudsplaining
6
+ Author: Kinnaird McQuade
7
+ Author-email: kinnairdm@gmail.com
8
+ License: UNKNOWN
9
+ Project-URL: Documentation, https://policy-sentry.readthedocs.io/
10
+ Project-URL: Example Report, https://opensource.salesforce.com/cloudsplaining
11
+ Project-URL: Code, https://github.com/salesforce/cloudsplaining/
12
+ Project-URL: Twitter, https://twitter.com/kmcquade3
13
+ Project-URL: Red Team Report, https://opensource.salesforce.com/policy_sentry
14
+ Keywords: aws iam roles policy policies privileges security
15
+ Platform: UNKNOWN
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: License :: OSI Approved :: MIT License
23
+ Classifier: Operating System :: OS Independent
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+
28
+ ## NOTE: This repo/project has been restored by Salesforce.
29
+
30
+ Cloudsplaining
31
+ --------------
32
+
33
+ Cloudsplaining is an AWS IAM Security Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report.
34
+
35
+ [![Tests](https://github.com/salesforce/cloudsplaining/workflows/Test/badge.svg)](https://github.com/salesforce/cloudsplaining/actions?query=workflow%3ATest)
36
+ [![Documentation Status](https://readthedocs.org/projects/cloudsplaining/badge/?version=latest)](https://cloudsplaining.readthedocs.io/en/latest/?badge=latest)
37
+ [![Join the chat at https://gitter.im/cloudsplaining](https://badges.gitter.im/cloudsplaining.svg)](https://gitter.im/cloudsplaining?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
38
+ [![Twitter](https://img.shields.io/twitter/url/https/twitter.com/kmcquade3.svg?style=social&label=Follow%20the%20author)](https://twitter.com/kmcquade3)
39
+ [![PyPI](https://img.shields.io/pypi/v/cloudsplaining)](https://pypi.org/project/cloudsplaining)
40
+ [![Python Version](https://img.shields.io/pypi/pyversions/cloudsplaining)](#)
41
+ [![Downloads](https://static.pepy.tech/badge/cloudsplaining)](https://pepy.tech/project/cloudsplaining)
42
+
43
+ * [Example report](https://opensource.salesforce.com/cloudsplaining/)
44
+
45
+ > ![](https://github.com/salesforce/cloudsplaining/raw/master/docs/_images/cloudsplaining-report.gif)
46
+
47
+ ## Documentation
48
+
49
+ For full documentation, please visit the [project on ReadTheDocs](https://cloudsplaining.readthedocs.io/en/latest/).
50
+
51
+ * [Installation](#installation)
52
+ * [Cheatsheet](#cheatsheet)
53
+ * [Example report](https://opensource.salesforce.com/cloudsplaining/)
54
+
55
+ ## Overview
56
+
57
+ Cloudsplaining identifies violations of least privilege in AWS IAM policies and generates a pretty HTML report with a triage worksheet. It can scan all the policies in your AWS account or it can scan a single policy file.
58
+
59
+ It helps to identify IAM actions that do not leverage resource constraints. It also helps prioritize the remediation process by flagging IAM policies that present the following risks to the AWS account in question without restriction:
60
+ * Data Exfiltration (`s3:GetObject`, `ssm:GetParameter`, `secretsmanager:GetSecretValue`)
61
+ * Infrastructure Modification
62
+ * Resource Exposure (the ability to modify resource-based policies)
63
+ * Privilege Escalation (based on Rhino Security Labs research)
64
+
65
+ Cloudsplaining also identifies IAM Roles that can be assumed by AWS Compute Services (such as EC2, ECS, EKS, or Lambda), as they can present greater risk than user-defined roles - especially if the AWS Compute service is on an instance that is directly or indirectly exposed to the internet. Flagging these roles is particularly useful to penetration testers (or attackers) under certain scenarios. For example, if an attacker obtains privileges to execute [ssm:SendCommand](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_SendCommand.html) and there are privileged EC2 instances with the SSM agent installed, they can effectively have the privileges of those EC2 instances. Remote Code Execution via AWS Systems Manager Agent was already a known escalation/exploitation path, but Cloudsplaining can make the process of identifying theses cases easier. See the [sample report](https://opensource.salesforce.com/cloudsplaining/#executive-summary) for some examples.
66
+
67
+ You can also specify a custom exclusions file to filter out results that are False Positives for various reasons. For example, User Policies are permissive by design, whereas System roles are generally more restrictive. You might also have exclusions that are specific to your organization's multi-account strategy or AWS application architecture.
68
+
69
+
70
+ ## Motivation
71
+
72
+ [Policy Sentry](https://engineering.salesforce.com/salesforce-cloud-security-automating-least-privilege-in-aws-iam-with-policy-sentry-b04fe457b8dc) revealed to us that it is possible to finally write IAM policies according to least privilege in a scalable manner. Before Policy Sentry was released, it was too easy to find IAM policy documents that lacked resource constraints. Consider the policy below, which allows the IAM principal (a role or user) to run `s3:PutObject` on any S3 bucket in the AWS account:
73
+
74
+ ```json
75
+ {
76
+ "Version": "2012-10-17",
77
+ "Statement": [
78
+ {
79
+ "Effect": "Allow",
80
+ "Action": [
81
+ "s3:PutObject"
82
+ ],
83
+ "Resource": "*"
84
+ }
85
+ ]
86
+ }
87
+ ```
88
+
89
+ This is bad. Ideally, access should be restricted according to resource ARNs, like so:
90
+
91
+ ```json
92
+ {
93
+ "Version": "2012-10-17",
94
+ "Statement": [
95
+ {
96
+ "Effect": "Allow",
97
+ "Action": [
98
+ "s3:GetObject"
99
+ ],
100
+ "Resource": "arn:aws:s3:::my-bucket/*"
101
+ }
102
+ ]
103
+ }
104
+ ```
105
+
106
+ Policy Sentry [makes it really easy to do this](https://github.com/salesforce/policy_sentry/#policy-sentry). Once Infrastructure as Code developers or AWS Administrators gain familiarity with the tool (which is quite easy to use), we've found that adoption starts very quickly. **However**, if you've been using AWS, there is probably a very large backlog of IAM policies that could use an uplift. If you have hundreds of AWS accounts with dozens of policies in each, how can we lock down those AWS accounts by programmatically identifying the policies that should be fixed?
107
+
108
+ That's why we wrote Cloudsplaining.
109
+
110
+ Cloudsplaining identifies violations of least privilege in AWS IAM policies and generates a pretty HTML report with a triage worksheet. It can scan all the policies in your AWS account or it can scan a single policy file.
111
+
112
+ ## Installation
113
+
114
+ #### Homebrew
115
+
116
+ ```bash
117
+ brew tap salesforce/cloudsplaining https://github.com/salesforce/cloudsplaining
118
+ brew install cloudsplaining
119
+ ```
120
+
121
+ #### Pip3
122
+
123
+ ```bash
124
+ pip3 install --user cloudsplaining
125
+ ```
126
+
127
+ * Now you should be able to execute `cloudsplaining` from command line by running `cloudsplaining --help`.
128
+
129
+ #### Shell completion
130
+
131
+ To enable Bash completion, put this in your `.bashrc`:
132
+
133
+ ```bash
134
+ eval "$(_CLOUDSPLAINING_COMPLETE=bash_source cloudsplaining)"
135
+ ```
136
+
137
+ To enable ZSH completion, put this in your .zshrc:
138
+
139
+ ```bash
140
+ eval "$(_CLOUDSPLAINING_COMPLETE=zsh_source cloudsplaining)"
141
+ ```
142
+
143
+ ### Scanning a single IAM policy
144
+
145
+ You can also scan a single policy file to identify risks instead of an entire account.
146
+
147
+ ```bash
148
+ cloudsplaining scan-policy-file --input-file examples/policies/explicit-actions.json
149
+ ```
150
+
151
+ The output will include a finding description and a list of the IAM actions that do not leverage resource constraints.
152
+
153
+ The output will resemble the following:
154
+
155
+ ```console
156
+ Issue found: Data Exfiltration
157
+ Actions: s3:GetObject
158
+
159
+ Issue found: Resource Exposure
160
+ Actions: ecr:DeleteRepositoryPolicy, ecr:SetRepositoryPolicy, s3:BypassGovernanceRetention, s3:DeleteAccessPointPolicy, s3:DeleteBucketPolicy, s3:ObjectOwnerOverrideToBucketOwner, s3:PutAccessPointPolicy, s3:PutAccountPublicAccessBlock, s3:PutBucketAcl, s3:PutBucketPolicy, s3:PutBucketPublicAccessBlock, s3:PutObjectAcl, s3:PutObjectVersionAcl
161
+
162
+ Issue found: Unrestricted Infrastructure Modification
163
+ Actions: ecr:BatchDeleteImage, ecr:CompleteLayerUpload, ecr:CreateRepository, ecr:DeleteLifecyclePolicy, ecr:DeleteRepository, ecr:DeleteRepositoryPolicy, ecr:InitiateLayerUpload, ecr:PutImage, ecr:PutImageScanningConfiguration, ecr:PutImageTagMutability, ecr:PutLifecyclePolicy, ecr:SetRepositoryPolicy, ecr:StartImageScan, ecr:StartLifecyclePolicyPreview, ecr:TagResource, ecr:UntagResource, ecr:UploadLayerPart, s3:AbortMultipartUpload, s3:BypassGovernanceRetention, s3:CreateAccessPoint, s3:CreateBucket, s3:DeleteAccessPoint, s3:DeleteAccessPointPolicy, s3:DeleteBucket, s3:DeleteBucketPolicy, s3:DeleteBucketWebsite, s3:DeleteObject, s3:DeleteObjectTagging, s3:DeleteObjectVersion, s3:DeleteObjectVersionTagging, s3:GetObject, s3:ObjectOwnerOverrideToBucketOwner, s3:PutAccelerateConfiguration, s3:PutAccessPointPolicy, s3:PutAnalyticsConfiguration, s3:PutBucketAcl, s3:PutBucketCORS, s3:PutBucketLogging, s3:PutBucketNotification, s3:PutBucketObjectLockConfiguration, s3:PutBucketPolicy, s3:PutBucketPublicAccessBlock, s3:PutBucketRequestPayment, s3:PutBucketTagging, s3:PutBucketVersioning, s3:PutBucketWebsite, s3:PutEncryptionConfiguration, s3:PutInventoryConfiguration, s3:PutLifecycleConfiguration, s3:PutMetricsConfiguration, s3:PutObject, s3:PutObjectAcl, s3:PutObjectLegalHold, s3:PutObjectRetention, s3:PutObjectTagging, s3:PutObjectVersionAcl, s3:PutObjectVersionTagging, s3:PutReplicationConfiguration, s3:ReplicateDelete, s3:ReplicateObject, s3:ReplicateTags, s3:RestoreObject, s3:UpdateJobPriority, s3:UpdateJobStatus
164
+
165
+ ```
166
+
167
+ ### Scanning an entire AWS Account
168
+
169
+ #### Downloading Account Authorization Details
170
+
171
+ We can scan an entire AWS account and generate reports. To do this, we leverage the AWS IAM [get-account-authorization-details](https://docs.aws.amazon.com/cli/latest/reference/iam/get-account-authorization-details.html) API call, which downloads a large JSON file (around 100KB per account) that contains all of the IAM details for the account. This includes data on users, groups, roles, customer-managed policies, and AWS-managed policies.
172
+
173
+ * You must have AWS credentials configured that can be used by the CLI.
174
+
175
+ * You must have the privileges to run [iam:GetAccountAuthorizationDetails](https://docs.aws.amazon.com/IAM/latest/APIReference/API_GetAccountAuthorizationDetails.html). The `arn:aws:iam::aws:policy/SecurityAudit` policy includes this, as do many others that allow Read access to the IAM Service.
176
+
177
+ * To download the account authorization details, ensure you are authenticated to AWS, then run `cloudsplaining`'s `download` command:
178
+
179
+ ```bash
180
+ cloudsplaining download
181
+ ```
182
+
183
+ * If you prefer to use your `~/.aws/credentials` file instead of environment variables, you can specify the profile name:
184
+
185
+ ```bash
186
+ cloudsplaining download --profile myprofile
187
+ ```
188
+
189
+ It will download a JSON file in your current directory that contains your account authorization detail information.
190
+
191
+ #### Create Exclusions file
192
+
193
+ Cloudsplaining tool does not attempt to understand the context behind everything in your AWS account. It's possible to understand the context behind some of these things programmatically - whether the policy is applied to an instance profile, whether the policy is attached, whether inline IAM policies are in use, and whether or not AWS Managed Policies are in use. **Only you know the context behind the design of your AWS infrastructure and the IAM strategy**.
194
+
195
+ As such, it's important to eliminate False Positives that are context-dependent. You can do this with an exclusions file. We've included a command that will generate an exclusions file for you so you don't have to remember the required format.
196
+
197
+ You can create an exclusions template via the following command:
198
+
199
+ ```bash
200
+ cloudsplaining create-exclusions-file
201
+ ```
202
+
203
+ This will generate a file in your current directory titled `exclusions.yml`.
204
+
205
+ Now when you run the `scan` command, you can use the exclusions file like this:
206
+
207
+ ```bash
208
+ cloudsplaining scan --exclusions-file exclusions.yml --input-file examples/files/example.json --output examples/files/
209
+ ```
210
+
211
+ For more information on the structure of the exclusions file, see [Filtering False Positives](#filtering-false-positives)
212
+
213
+ #### Scanning the Authorization Details file
214
+
215
+ Now that we've downloaded the account authorization file, we can scan *all* of the AWS IAM policies with `cloudsplaining`.
216
+
217
+ Run the following command:
218
+
219
+ ```bash
220
+ cloudsplaining scan --exclusions-file exclusions.yml --input-file examples/files/example.json --output examples/files/
221
+ ```
222
+
223
+ It will create an HTML report like [this](https://opensource.salesforce.com/cloudsplaining/):
224
+
225
+ > ![](docs/_images/cloudsplaining-report.gif)
226
+
227
+
228
+ It will also create a raw JSON data file:
229
+
230
+ * `default-iam-results.json`: This contains the raw JSON output of the report. You can use this data file for operating on the scan results for various purposes. For example, you could write a Python script that parses this data and opens up automated JIRA issues or Salesforce Work Items. An example entry is shown below. The full example can be viewed at [examples/files/iam-results-example.json](examples/files/iam-results-example.json)
231
+
232
+ ```json
233
+ {
234
+ "example-authz-details": [
235
+ {
236
+ "AccountID": "012345678901",
237
+ "ManagedBy": "Customer",
238
+ "PolicyName": "InsecureUserPolicy",
239
+ "Arn": "arn:aws:iam::012345678901:user/userwithlotsofpermissions",
240
+ "ActionsCount": 2,
241
+ "ServicesCount": 1,
242
+ "Actions": [
243
+ "s3:PutObject",
244
+ "s3:PutObjectAcl"
245
+ ],
246
+ "Services": [
247
+ "s3"
248
+ ]
249
+ }
250
+ ]
251
+ }
252
+ ```
253
+
254
+
255
+ See the [examples/files](examples/files) folder for sample output.
256
+
257
+ #### Filtering False Positives
258
+
259
+ Resource constraints are best practice - especially for system roles/instance profiles - but sometimes, these are by design. For example, consider a situation where a custom IAM policy is used on an instance profile for an EC2 instance that provisions Terraform. *In this case, broad permissions are design requirements* - so we don't want to include these in the results.
260
+
261
+ You can create an exclusions template via the following command:
262
+
263
+ ```bash
264
+ cloudsplaining create-exclusions-file
265
+ ```
266
+
267
+ This will generate a file in your current directory titled `exclusions.yml`.
268
+
269
+ The default exclusions file looks like this:
270
+
271
+ ```yaml
272
+ # Policy names to exclude from evaluation
273
+ # Suggestion: Add policies here that are known to be overly permissive by design, after you run the initial report.
274
+ policies:
275
+ - "AWSServiceRoleFor*"
276
+ - "*ServiceRolePolicy"
277
+ - "*ServiceLinkedRolePolicy"
278
+ - "AdministratorAccess" # Otherwise, this will take a long time
279
+ - "service-role*"
280
+ - "aws-service-role*"
281
+ # Don't evaluate these roles, users, or groups as part of the evaluation
282
+ roles:
283
+ - "service-role*"
284
+ - "aws-service-role*"
285
+ users:
286
+ - ""
287
+ groups:
288
+ - ""
289
+ # Read-only actions to include in the results, such as s3:GetObject
290
+ # By default, it includes Actions that could lead to Data Exfiltration
291
+ include-actions:
292
+ - "s3:GetObject"
293
+ - "ssm:GetParameter"
294
+ - "ssm:GetParameters"
295
+ - "ssm:GetParametersByPath"
296
+ - "secretsmanager:GetSecretValue"
297
+ # Write actions to include from the results, such as kms:Decrypt
298
+ exclude-actions:
299
+ - ""
300
+ ```
301
+
302
+ * Make any additions or modifications that you want.
303
+ * Under `policies`, list the path of policy names that you want to exclude.
304
+ * If you want to exclude a role titled `MyRole`, list `MyRole` or `MyR*` in the `roles` list.
305
+ * You can follow the same approach for `users` and `groups` list.
306
+
307
+ Now when you run the `scan` command, you can use the exclusions file like this:
308
+
309
+ ```bash
310
+ cloudsplaining scan --exclusions-file exclusions.yml --input-file examples/files/example.json --output examples/files/
311
+ ```
312
+
313
+ ### Scanning Multiple AWS Accounts
314
+
315
+ If your IAM user or IAM role has `sts:AssumeRole` permissions to a common IAM role across multiple AWS accounts, you can use the `scan-multi-account` command.
316
+
317
+ This diagram depicts how the process works:
318
+
319
+ ![Diagram for scanning multiple AWS accounts with Cloudsplaining](docs/_images/scan-multiple-accounts.png)
320
+
321
+
322
+ > Note: If you are new to setting up cross-account access, check out [the official AWS Tutorial on Delegating access across AWS accounts using IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html). That can help you set up the architecture above.
323
+
324
+
325
+ * First, you'll need to create the multi-account config file. Run the following command:
326
+
327
+ ```bash
328
+ cloudsplaining create-multi-account-config-file \
329
+ -o multi-account-config.yml
330
+ ```
331
+
332
+ * This will generate a file called `multi-account-config.yml` with the following contents:
333
+
334
+ ```yaml
335
+ accounts:
336
+ default_account: 123456789012
337
+ prod: 123456789013
338
+ test: 123456789014
339
+ ```
340
+
341
+ > Note: Observe how the format of the file above includes `account_name: accountID`. Edit the file contents to match your desired account name and account ID. Include as many account IDs as you like.
342
+
343
+
344
+ For the next step, let's say that:
345
+ * We have a role in the target accounts that is called `CommonSecurityRole`.
346
+ * The credentials for your IAM user are under the AWS Credentials profile called `scanning-user`.
347
+ * That user has `sts:AssumeRole` permissions to assume the `CommonSecurityRole` in all your target accounts specified in the YAML file we created previously.
348
+ * You want to save the output to an S3 bucket called `my-results-bucket`
349
+
350
+ Using the data above, you can run the following command:
351
+
352
+ ```bash
353
+ cloudsplaining scan-multi-account \
354
+ -c multi-account-config.yml \
355
+ --profile scanning-user \
356
+ --role-name CommonSecurityRole \
357
+ --output-bucket my-results-bucket
358
+ ```
359
+
360
+ > Note that if you run the above without the `--profile` flag, it will execute in the standard [AWS Credentials order of precedence](https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html#credentials-default) (i.e., Environment variables, credentials profiles, ECS container credentials, then finally EC2 Instance Profile credentials).
361
+
362
+
363
+ ## Cheatsheet
364
+
365
+ ```bash
366
+ # Download authorization details
367
+ cloudsplaining download
368
+ # Download from a specific AWS profile
369
+ cloudsplaining download --profile someprofile
370
+
371
+ # Scan Authorization details
372
+ cloudsplaining scan --input-file default.json
373
+ # Scan Authorization details with custom exclusions
374
+ cloudsplaining scan --input-file default.json --exclusions-file exclusions.yml
375
+
376
+ # Scan Policy Files
377
+ cloudsplaining scan-policy-file --input-file examples/policies/wildcards.json
378
+ cloudsplaining scan-policy-file --input-file examples/policies/wildcards.json --exclusions-file examples/example-exclusions.yml
379
+
380
+ # Scan Multiple Accounts
381
+ # Generate the multi account config file
382
+ cloudsplaining create-multi-account-config-file -o accounts.yml
383
+ cloudsplaining scan-multi-account -c accounts.yml -r TargetRole --output-directory ./
384
+ ```
385
+
386
+ ## FAQ
387
+
388
+ **Will it scan all policies by default?**
389
+
390
+ No, it will only scan policies that are attached to IAM principals.
391
+
392
+ **Will the download command download all policy versions?**
393
+
394
+ Not by default. If you want to do this, specify the `--include-non-default-policy-versions` flag. Note that the `scan` tool does not currently operate on non-default versions.
395
+
396
+ **I followed the installation instructions but can't execute the program via command line at all. What do I do?**
397
+
398
+ This is likely an issue with your PATH. Your PATH environment variable is not considering the binary packages installed by `pip3`. On a Mac, you can likely fix this by entering the command below, depending on the versions you have installed. YMMV.
399
+
400
+ ```bash
401
+ export PATH=$HOME/Library/Python/3.7/bin/:$PATH
402
+ ```
403
+
404
+ **I followed the installation instructions, but I am receiving a `ModuleNotFoundError` that says `No module named policy_sentry.analysis.expand`. What should I do?**
405
+
406
+ Try upgrading to the latest version of Cloudsplaining. This error was fixed in version 0.0.10.
407
+
408
+ ## References
409
+
410
+ * [Policy Sentry](https://github.com/salesforce/policy_sentry/) by [Kinnaird McQuade](https://twitter.com/kmcquade3) at Salesforce
411
+ * [Parliament](https://github.com/duo-labs/parliament/) by [Scott Piper](https://twitter.com/0xdabbad00) at [Summit Route](http://summitroute.com/) and Duo Labs.
412
+ * [AWS Privilege Escalation Methods](https://github.com/RhinoSecurityLabs/AWS-IAM-Privilege-Escalation) by [Spencer Gietzen](https://twitter.com/SpenGietz) at Rhino Security Labs
413
+ * [Understanding Access Level Summaries within Policy Summaries](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_understand-policy-summary-access-level-summaries.html)
414
+ * [Leveraging next-generation blockchain-based AI across multiple service meshes to transparently automate multi-cloud IAM wizardry :mage_man:](http://kmcquade.com/rick.html)
415
+
416
+
@@ -104,13 +104,13 @@ pip3 install --user cloudsplaining
104
104
  To enable Bash completion, put this in your `.bashrc`:
105
105
 
106
106
  ```bash
107
- eval "$(_CLOUDSPLAINING_COMPLETE=source cloudsplaining)"
107
+ eval "$(_CLOUDSPLAINING_COMPLETE=bash_source cloudsplaining)"
108
108
  ```
109
109
 
110
110
  To enable ZSH completion, put this in your .zshrc:
111
111
 
112
112
  ```bash
113
- eval "$(_CLOUDSPLAINING_COMPLETE=source_zsh cloudsplaining)"
113
+ eval "$(_CLOUDSPLAINING_COMPLETE=zsh_source cloudsplaining)"
114
114
  ```
115
115
 
116
116
  ### Scanning a single IAM policy
@@ -1,16 +1,15 @@
1
1
  # pylint: disable=missing-module-docstring
2
+ from __future__ import annotations
3
+
2
4
  import logging
3
5
  import sys
4
6
 
5
7
  # Set default logging handler to avoid "No handler found" warnings.
6
- from logging import NullHandler
7
-
8
+ # from logging import NullHandler
8
9
  # logging.getLogger(__name__).addHandler(NullHandler())
9
10
  # Uncomment to get the full debug logs.
10
11
  # 2020-10-06 10:04:17,200 - root - DEBUG - Leveraging the bundled IAM Definition.
11
12
  # Need to figure out how to get click_log to do this for me.
12
- from typing import Union, Optional
13
-
14
13
  logger = logging.getLogger(__name__)
15
14
  logger.setLevel(logging.WARNING)
16
15
  handler = logging.StreamHandler(sys.stdout)
@@ -23,8 +22,8 @@ logger.addHandler(handler)
23
22
  name = "cloudsplaining" # pylint: disable=invalid-name
24
23
 
25
24
 
26
- def change_log_level(log_level: Union[int, str]) -> None:
27
- """"Change log level of module logger"""
25
+ def change_log_level(log_level: int | str) -> None:
26
+ """ "Change log level of module logger"""
28
27
  logger.setLevel(log_level)
29
28
 
30
29
 
@@ -32,7 +31,7 @@ def change_log_level(log_level: Union[int, str]) -> None:
32
31
  def set_stream_logger(
33
32
  name: str = "cloudsplaining",
34
33
  level: int = logging.DEBUG,
35
- format_string: Optional[str] = None,
34
+ format_string: str | None = None,
36
35
  ) -> None:
37
36
  """
38
37
  Add a stream handler for the given name and level to the logging module.
@@ -71,10 +70,10 @@ def set_log_level(verbose: int) -> None:
71
70
  :return:
72
71
  """
73
72
  if verbose == 1:
74
- set_stream_logger(level=getattr(logging, "WARNING"))
73
+ set_stream_logger(level=logging.WARNING)
75
74
  elif verbose == 2:
76
- set_stream_logger(level=getattr(logging, "INFO"))
75
+ set_stream_logger(level=logging.INFO)
77
76
  elif verbose >= 3:
78
- set_stream_logger(level=getattr(logging, "DEBUG"))
77
+ set_stream_logger(level=logging.DEBUG)
79
78
  else:
80
- set_stream_logger(level=getattr(logging, "CRITICAL"))
79
+ set_stream_logger(level=logging.CRITICAL)
@@ -5,9 +5,11 @@
5
5
  # For full license text, see the LICENSE file in the repo root
6
6
  # or https://opensource.org/licenses/BSD-3-Clause
7
7
  """
8
- Cloudsplaining is an AWS IAM Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report with a triage worksheet.
8
+ Cloudsplaining is an AWS IAM Assessment tool that identifies violations of least privilege and generates a risk-prioritized HTML report with a triage worksheet.
9
9
  """
10
+
10
11
  import click
12
+
11
13
  from cloudsplaining import command
12
14
  from cloudsplaining.bin.version import __version__
13
15
 
@@ -1,2 +1,2 @@
1
1
  # pylint: disable=missing-module-docstring
2
- __version__ = '0.6.3'
2
+ __version__ = "0.8.0"
@@ -0,0 +1,11 @@
1
+ # ruff: noqa: F401
2
+ # pylint: disable=missing-module-docstring
3
+ from cloudsplaining.command import (
4
+ create_exclusions_file,
5
+ create_multi_account_config_file,
6
+ download,
7
+ expand_policy,
8
+ scan,
9
+ scan_multi_account,
10
+ scan_policy_file,
11
+ )
@@ -2,17 +2,20 @@
2
2
  Create YML Template files for the exclusions template command.
3
3
  This way, users don't have to remember exactly how to phrase the yaml files, since this command creates it for them.
4
4
  """
5
+
5
6
  # Copyright (c) 2020, salesforce.com, inc.
6
7
  # All rights reserved.
7
8
  # Licensed under the BSD 3-Clause license.
8
9
  # For full license text, see the LICENSE file in the repo root
9
10
  # or https://opensource.org/licenses/BSD-3-Clause
10
- import os
11
11
  import logging
12
+ import os
13
+
12
14
  import click
13
- from cloudsplaining.shared.constants import EXCLUSIONS_TEMPLATE
15
+
14
16
  from cloudsplaining import set_log_level
15
17
  from cloudsplaining.shared import utils
18
+ from cloudsplaining.shared.constants import EXCLUSIONS_TEMPLATE
16
19
 
17
20
  logger = logging.getLogger(__name__)
18
21
 
@@ -21,7 +24,14 @@ logger = logging.getLogger(__name__)
21
24
  context_settings=dict(max_content_width=160),
22
25
  short_help="Creates a YML file to be used as a custom exclusions template",
23
26
  )
24
- @click.option("-o", "--output-file", type=click.Path(exists=False), default=os.path.join(os.getcwd(), "exclusions.yml"), required=True, help="Relative path to output file where we want to store the exclusions template.")
27
+ @click.option(
28
+ "-o",
29
+ "--output-file",
30
+ type=click.Path(exists=False),
31
+ default=os.path.join(os.getcwd(), "exclusions.yml"),
32
+ required=True,
33
+ help="Relative path to output file where we want to store the exclusions template.",
34
+ )
25
35
  @click.option("--verbose", "-v", "verbosity", count=True)
26
36
  def create_exclusions_file(output_file: str, verbosity: int) -> None:
27
37
  """
@@ -30,7 +40,7 @@ def create_exclusions_file(output_file: str, verbosity: int) -> None:
30
40
  """
31
41
  set_log_level(verbosity)
32
42
 
33
- with open(output_file, "a") as file_obj:
43
+ with open(output_file, "a", encoding="utf-8") as file_obj:
34
44
  for line in EXCLUSIONS_TEMPLATE:
35
45
  file_obj.write(line)
36
46
  utils.print_green(f"Success! Exclusions template file written to: {output_file}")
@@ -40,6 +50,4 @@ def create_exclusions_file(output_file: str, verbosity: int) -> None:
40
50
  )
41
51
  print("\tcloudsplaining download")
42
52
  print("You can use this with the scan command as shown below: ")
43
- print(
44
- "\tcloudsplaining scan --exclusions-file exclusions.yml --input-file default.json"
45
- )
53
+ print("\tcloudsplaining scan --exclusions-file exclusions.yml --input-file default.json")
@@ -2,17 +2,20 @@
2
2
  Create YML Template files for the exclusions template command.
3
3
  This way, users don't have to remember exactly how to phrase the yaml files, since this command creates it for them.
4
4
  """
5
+
5
6
  # Copyright (c) 2020, salesforce.com, inc.
6
7
  # All rights reserved.
7
8
  # Licensed under the BSD 3-Clause license.
8
9
  # For full license text, see the LICENSE file in the repo root
9
10
  # or https://opensource.org/licenses/BSD-3-Clause
10
- import os
11
11
  import logging
12
+ import os
13
+
12
14
  import click
13
- from cloudsplaining.shared.constants import MULTI_ACCOUNT_CONFIG_TEMPLATE
15
+
14
16
  from cloudsplaining import set_log_level
15
17
  from cloudsplaining.shared import utils
18
+ from cloudsplaining.shared.constants import MULTI_ACCOUNT_CONFIG_TEMPLATE
16
19
 
17
20
  logger = logging.getLogger(__name__)
18
21
  OK_GREEN = "\033[92m"
@@ -23,7 +26,15 @@ END = "\033[0m"
23
26
  context_settings=dict(max_content_width=160),
24
27
  short_help="Creates a YML file to be used for multi-account scanning",
25
28
  )
26
- @click.option("-o", "--output-file", "output_file", type=click.Path(exists=False), default=os.path.join(os.getcwd(), "multi-account-config.yml"), required=True, help="Relative path to output file where we want to store the multi account config template.")
29
+ @click.option(
30
+ "-o",
31
+ "--output-file",
32
+ "output_file",
33
+ type=click.Path(exists=False),
34
+ default=os.path.join(os.getcwd(), "multi-account-config.yml"),
35
+ required=True,
36
+ help="Relative path to output file where we want to store the multi account config template.",
37
+ )
27
38
  @click.option("-v", "--verbose", "verbosity", help="Log verbosity level.", count=True)
28
39
  def create_multi_account_config_file(output_file: str, verbosity: int) -> None:
29
40
  """
@@ -32,17 +43,13 @@ def create_multi_account_config_file(output_file: str, verbosity: int) -> None:
32
43
  set_log_level(verbosity)
33
44
 
34
45
  if os.path.exists(output_file):
35
- logger.debug(
36
- "%s exists. Removing the file and replacing its contents.", output_file
37
- )
46
+ logger.debug("%s exists. Removing the file and replacing its contents.", output_file)
38
47
  os.remove(output_file)
39
48
 
40
- with open(output_file, "a") as file_obj:
49
+ with open(output_file, "a", encoding="utf-8") as file_obj:
41
50
  for line in MULTI_ACCOUNT_CONFIG_TEMPLATE:
42
51
  file_obj.write(line)
43
- utils.print_green(
44
- f"Success! Multi-account config file written to: {os.path.relpath(output_file)}"
45
- )
52
+ utils.print_green(f"Success! Multi-account config file written to: {os.path.relpath(output_file)}")
46
53
  print(
47
54
  f"\nMake sure you edit the {os.path.relpath(output_file)} file and then run the scan-multi-account command, as shown below."
48
55
  )