|
8 | 8 | import os
|
9 | 9 | import json
|
10 | 10 | import logging
|
11 |
| -import configparser |
12 | 11 | from pathlib import Path
|
13 | 12 | import boto3
|
14 | 13 | import click
|
|
26 | 25 | @click.option(
|
27 | 26 | "--profile",
|
28 | 27 | type=str,
|
29 |
| - default="default", |
30 |
| - required=True, |
| 28 | + required=False, |
31 | 29 | help="Specify 'all' to authenticate to AWS and analyze *all* existing IAM policies. Specify a non-default "
|
32 | 30 | "profile here. Defaults to the 'default' profile.",
|
33 | 31 | )
|
|
37 | 35 | default=Path.cwd(),
|
38 | 36 | help="Path to store the output. Defaults to current directory.",
|
39 | 37 | )
|
40 |
| -@click.option( |
41 |
| - "--credentials-file", |
42 |
| - type=click.Path(exists=False), |
43 |
| - help="Path to the AWS credentials file.", |
44 |
| - default=str(Path.home()) + "/.aws/credentials", |
45 |
| -) |
46 | 38 | @click.option(
|
47 | 39 | "--include-non-default-policy-versions",
|
48 | 40 | is_flag=True,
|
|
51 | 43 | " Note that this will dramatically increase the size of the downloaded file.",
|
52 | 44 | )
|
53 | 45 | @click_log.simple_verbosity_option(logger)
|
54 |
| -def download(profile, output, credentials_file, include_non_default_policy_versions): |
| 46 | +def download(profile, output, include_non_default_policy_versions): |
55 | 47 | """
|
56 | 48 | Runs aws iam get-authorization-details on all accounts specified in the aws credentials file, and stores them in
|
57 | 49 | account-alias.json
|
58 | 50 | """
|
59 |
| - # Just default profile |
60 |
| - if profile == "default": |
61 |
| - profiles = ["default"] |
62 |
| - print("profile: default") |
63 |
| - # Get all profiles |
64 |
| - elif profile == "all": |
65 |
| - profiles = get_list_of_aws_profiles(credentials_file) |
66 |
| - print("profile: all profiles") |
67 |
| - print(profiles) |
68 |
| - else: |
69 |
| - credentials_file_profiles = get_list_of_aws_profiles(credentials_file) |
70 |
| - # If it exists in ~/.aws/credentials, |
71 |
| - if profile in credentials_file_profiles: |
72 |
| - print(f"profile: {profile}") |
73 |
| - profiles = [profile] |
74 |
| - else: |
75 |
| - raise Exception( |
76 |
| - "The profile %s is not in the ~/.aws/credentials file", profile |
77 |
| - ) |
78 |
| - for profile in profiles: |
79 |
| - print("Running get_account_authorization_details for profile: ", profile) |
80 |
| - get_account_authorization_details( |
81 |
| - profile, output, include_non_default_policy_versions |
82 |
| - ) |
83 |
| - |
84 |
| - |
85 |
| -def get_account_authorization_details( |
86 |
| - profile, output, include_non_default_policy_versions=False |
87 |
| -): |
88 |
| - """ |
89 |
| - Run aws iam get-account-authorization-details and store locally. |
90 |
| -
|
91 |
| - :param profile: Name of the profile in the AWS Credentials file |
92 |
| - :param output: The path of a directory to store the results. |
93 |
| - :param include_non_default_policy_versions: When downloading AWS managed policy documents, also include the non-default policy versions. Note that this will dramatically increase the size of the downloaded file. |
94 |
| - :return: |
95 |
| - """ |
96 |
| - |
97 |
| - def get_session_via_environment_variables(): |
98 |
| - aws_access_key_id = os.getenv("AWS_ACCESS_KEY_ID") |
99 |
| - aws_secret_access_key = os.getenv("AWS_SECRET_ACCESS_KEY") |
100 |
| - aws_session_token = os.getenv("AWS_SESSION_TOKEN") |
101 |
| - if aws_access_key_id and aws_secret_access_key and aws_session_token: |
102 |
| - session = boto3.Session( |
103 |
| - aws_access_key_id=aws_access_key_id, |
104 |
| - aws_secret_access_key=aws_secret_access_key, |
105 |
| - aws_session_token=aws_session_token, |
106 |
| - ) |
107 |
| - return session |
108 |
| - elif aws_access_key_id and aws_secret_access_key and not aws_session_token: |
109 |
| - print( |
110 |
| - "It looks like you are authenticating with static credentials rather than temporary credentials. " |
111 |
| - "Static credentials usage is a security concern. We suggest you use MFA to generate short lived " |
112 |
| - "credentials and set those as environment variables instead." |
113 |
| - ) |
114 |
| - session = boto3.Session( |
115 |
| - aws_access_key_id=aws_access_key_id, |
116 |
| - aws_secret_access_key=aws_secret_access_key, |
117 |
| - ) |
118 |
| - return session |
119 |
| - else: |
120 |
| - return False |
| 51 | + default_region = "us-east-1" |
| 52 | + session_data = {"region_name": default_region} |
121 | 53 |
|
122 |
| - config = Config(connect_timeout=5, retries={"max_attempts": 10}) |
123 |
| - if get_session_via_environment_variables(): |
124 |
| - print("AWS Credentials found in Environment variables.") |
125 |
| - boto3_session = get_session_via_environment_variables() |
| 54 | + if profile: |
| 55 | + session_data["profile_name"] = profile |
| 56 | + output_filename = os.path.join(output, f"{profile}.json") |
126 | 57 | else:
|
127 |
| - boto3_session = boto3.Session(profile_name=profile) |
| 58 | + output_filename = "default.json" |
128 | 59 |
|
129 |
| - iam_client = boto3_session.client("iam", config=config) |
| 60 | + session = boto3.Session(**session_data) |
| 61 | + config = Config(connect_timeout=5, retries={"max_attempts": 10}) |
| 62 | + iam_client = session.client("iam", config=config) |
130 | 63 |
|
131 | 64 | results = {
|
132 | 65 | "UserDetailList": [],
|
@@ -182,46 +115,9 @@ def get_session_via_environment_variables():
|
182 | 115 | }
|
183 | 116 | results["Policies"].append(entry)
|
184 | 117 |
|
185 |
| - filename = os.path.join(output, f"{profile}.json") |
186 |
| - if os.path.exists(filename): |
187 |
| - os.remove(filename) |
188 |
| - with open(filename, "w") as file: |
| 118 | + if os.path.exists(output_filename): |
| 119 | + os.remove(output_filename) |
| 120 | + with open(output_filename, "w") as file: |
189 | 121 | json.dump(results, file, indent=4, default=str)
|
190 |
| - print(f"Saved results to {filename}") |
| 122 | + print(f"Saved results to {output_filename}") |
191 | 123 | return 1
|
192 |
| - |
193 |
| - |
194 |
| -def get_list_of_aws_profiles(credentials_file): |
195 |
| - """Get a list of profiles from the AWS Credentials file""" |
196 |
| - config = configparser.RawConfigParser() |
197 |
| - config.read(credentials_file) |
198 |
| - sections = config.sections() |
199 |
| - legitimate_sections = [] |
200 |
| - for section in sections: |
201 |
| - # https://github.com/broamski/aws-mfa#credentials-file-setup |
202 |
| - broamski_suffix = "-long-term" |
203 |
| - # pylint: disable=no-else-continue |
204 |
| - if section.endswith(broamski_suffix): |
205 |
| - # skip it if it's not a real profile we want to evaluate |
206 |
| - continue |
207 |
| - else: |
208 |
| - legitimate_sections.append(section) |
209 |
| - return legitimate_sections |
210 |
| - |
211 |
| - |
212 |
| -def login(profile_name, service="iam"): |
213 |
| - """Log in to AWS and return a boto3 session.""" |
214 |
| - default_region = os.environ.get("AWS_REGION", "us-east-1") |
215 |
| - session_data = {"region_name": default_region} |
216 |
| - if profile_name: |
217 |
| - session_data["profile_name"] = profile_name |
218 |
| - |
219 |
| - session = boto3.Session(**session_data) |
220 |
| - |
221 |
| - # Return the service requested by the function - either sts or iam |
222 |
| - if service: |
223 |
| - this_session = session.client(service) |
224 |
| - # By default return IAM |
225 |
| - else: |
226 |
| - this_session = session.client("iam") |
227 |
| - return this_session |
0 commit comments