Browse code

Merge pull request #966 from Trane9991/master

Issue #906 add support for $AWS_PROFILE

Florent Viard authored on 2018/06/04 00:23:46
Showing 1 changed files
... ...
@@ -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 = []