Issue #906 add support for $AWS_PROFILE
Florent Viard authored on 2018/06/04 00:23:46... | ... |
@@ -24,6 +24,12 @@ except ImportError: |
24 | 24 |
import http.client as httplib |
25 | 25 |
import locale |
26 | 26 |
|
27 |
+try: |
|
28 |
+ from configparser import NoOptionError, NoSectionError, MissingSectionHeaderError, ConfigParser as PyConfigParser |
|
29 |
+except ImportError: |
|
30 |
+ # Python2 fallback code |
|
31 |
+ from ConfigParser import NoOptionError, NoSectionError, MissingSectionHeaderError, ConfigParser as PyConfigParser |
|
32 |
+ |
|
27 | 33 |
try: |
28 | 34 |
unicode |
29 | 35 |
except NameError: |
... | ... |
@@ -211,8 +217,8 @@ class Config(object): |
211 | 211 |
try: |
212 | 212 |
self.read_config_file(configfile) |
213 | 213 |
except IOError: |
214 |
- if 'AWS_CREDENTIAL_FILE' in os.environ: |
|
215 |
- self.env_config() |
|
214 |
+ if 'AWS_CREDENTIAL_FILE' in os.environ or 'AWS_PROFILE' in os.environ: |
|
215 |
+ self.aws_credential_file() |
|
216 | 216 |
|
217 | 217 |
# override these if passed on the command-line |
218 | 218 |
if access_key and secret_key: |
... | ... |
@@ -275,38 +281,74 @@ class Config(object): |
275 | 275 |
except: |
276 | 276 |
warning("Could not refresh role") |
277 | 277 |
|
278 |
- def env_config(self): |
|
279 |
- cred_content = "" |
|
278 |
+ def aws_credential_file(self): |
|
280 | 279 |
try: |
281 |
- cred_file = open(os.environ['AWS_CREDENTIAL_FILE'],'r') |
|
282 |
- cred_content = cred_file.read() |
|
280 |
+ aws_credential_file = os.path.expanduser('~/.aws/credentials') |
|
281 |
+ if 'AWS_CREDENTIAL_FILE' in os.environ and os.path.isfile(os.environ['AWS_CREDENTIAL_FILE']): |
|
282 |
+ aws_credential_file = config_unicodise(os.environ['AWS_CREDENTIAL_FILE']) |
|
283 |
+ |
|
284 |
+ config = PyConfigParser() |
|
285 |
+ |
|
286 |
+ debug("Reading AWS credentials from %s" % (aws_credential_file)) |
|
287 |
+ try: |
|
288 |
+ config.read(aws_credential_file) |
|
289 |
+ except MissingSectionHeaderError: |
|
290 |
+ # if header is missing, this could be deprecated credentials file format |
|
291 |
+ # as described here: https://blog.csanchez.org/2011/05/ |
|
292 |
+ # then do the hacky-hack and add default header |
|
293 |
+ # to be able to read the file with PyConfigParser() |
|
294 |
+ config_string = None |
|
295 |
+ with open(aws_credential_file, 'r') as f: |
|
296 |
+ config_string = '[default]\n' + f.read() |
|
297 |
+ config.read_string(config_string.decode('utf-8')) |
|
298 |
+ |
|
299 |
+ |
|
300 |
+ profile = config_unicodise(os.environ.get('AWS_PROFILE', "default")) |
|
301 |
+ debug("Using AWS profile '%s'" % (profile)) |
|
302 |
+ |
|
303 |
+ # get_key - helper function to read the aws profile credentials |
|
304 |
+ # including the legacy ones as described here: https://blog.csanchez.org/2011/05/ |
|
305 |
+ def get_key(profile, key, legacy_key, print_warning=True): |
|
306 |
+ result = None |
|
307 |
+ |
|
308 |
+ try: |
|
309 |
+ result = config.get(profile, key) |
|
310 |
+ except NoOptionError as e: |
|
311 |
+ if print_warning: # we may want to skip warning message for optional keys |
|
312 |
+ warning("Couldn't find key '%s' for the AWS Profile '%s' in the credentials file '%s'" % (e.option, e.section, aws_credential_file)) |
|
313 |
+ if legacy_key: # if the legacy_key defined and original one wasn't found, try read the legacy_key |
|
314 |
+ try: |
|
315 |
+ key = legacy_key |
|
316 |
+ profile = "default" |
|
317 |
+ result = config.get(profile, key) |
|
318 |
+ warning( |
|
319 |
+ "Legacy configuratin key '%s' used, " % (key) + |
|
320 |
+ "please use the standardized config format as described here: " + |
|
321 |
+ "https://aws.amazon.com/blogs/security/a-new-and-standardized-way-to-manage-credentials-in-the-aws-sdks/" |
|
322 |
+ ) |
|
323 |
+ except NoOptionError as e: |
|
324 |
+ pass |
|
325 |
+ |
|
326 |
+ if result: |
|
327 |
+ debug("Found the configuration option '%s' for the AWS Profile '%s' in the credentials file %s" % (key, profile, aws_credential_file)) |
|
328 |
+ return result |
|
329 |
+ |
|
330 |
+ profile_access_key = get_key(profile, "aws_access_key_id", "AWSAccessKeyId") |
|
331 |
+ if profile_access_key: |
|
332 |
+ Config().update_option('access_key', config_unicodise(profile_access_key)) |
|
333 |
+ |
|
334 |
+ profile_secret_key = get_key(profile, "aws_secret_access_key", "AWSSecretKey") |
|
335 |
+ if profile_secret_key: |
|
336 |
+ Config().update_option('secret_key', config_unicodise(profile_secret_key)) |
|
337 |
+ |
|
338 |
+ profile_access_token = get_key(profile, "aws_session_token", None, False) |
|
339 |
+ if profile_access_token: |
|
340 |
+ Config().update_option('access_token', config_unicodise(profile_access_token)) |
|
341 |
+ |
|
283 | 342 |
except IOError as e: |
284 |
- debug("Error %d accessing credentials file %s" % (e.errno,os.environ['AWS_CREDENTIAL_FILE'])) |
|
285 |
- r_data = re.compile("^\s*(?P<orig_key>\w+)\s*=\s*(?P<value>.*)") |
|
286 |
- r_quotes = re.compile("^\"(.*)\"\s*$") |
|
287 |
- if len(cred_content)>0: |
|
288 |
- for line in cred_content.splitlines(): |
|
289 |
- is_data = r_data.match(line) |
|
290 |
- if is_data: |
|
291 |
- data = is_data.groupdict() |
|
292 |
- if r_quotes.match(data["value"]): |
|
293 |
- data["value"] = data["value"][1:-1] |
|
294 |
- if data["orig_key"] == "AWSAccessKeyId" \ |
|
295 |
- or data["orig_key"] == "aws_access_key_id": |
|
296 |
- data["key"] = "access_key" |
|
297 |
- elif data["orig_key"]=="AWSSecretKey" \ |
|
298 |
- or data["orig_key"]=="aws_secret_access_key": |
|
299 |
- data["key"] = "secret_key" |
|
300 |
- else: |
|
301 |
- debug("env_config: key = %r will be ignored", data["orig_key"]) |
|
302 |
- |
|
303 |
- if "key" in data: |
|
304 |
- Config().update_option(data["key"], data["value"]) |
|
305 |
- if data["key"] in ("access_key", "secret_key", "gpg_passphrase"): |
|
306 |
- print_value = ("%s...%d_chars...%s") % (data["value"][:2], len(data["value"]) - 3, data["value"][-1:]) |
|
307 |
- else: |
|
308 |
- print_value = data["value"] |
|
309 |
- debug("env_Config: %s->%s" % (data["key"], print_value)) |
|
343 |
+ warning("%d accessing credentials file %s" % (e.errno, aws_credential_file)) |
|
344 |
+ except NoSectionError as e: |
|
345 |
+ warning("Couldn't find AWS Profile '%s' in the credentials file '%s'" % (profile, aws_credential_file)) |
|
310 | 346 |
|
311 | 347 |
def option_list(self): |
312 | 348 |
retval = [] |