OLD | NEW |
(Empty) | |
| 1 # Copyright (c) 2012 Mitch Garnaat http://garnaat.org/ |
| 2 # Copyright (c) 2012 Amazon.com, Inc. or its affiliates. |
| 3 # All Rights Reserved |
| 4 # |
| 5 # Permission is hereby granted, free of charge, to any person obtaining a |
| 6 # copy of this software and associated documentation files (the |
| 7 # "Software"), to deal in the Software without restriction, including |
| 8 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 9 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 10 # persons to whom the Software is furnished to do so, subject to the fol- |
| 11 # lowing conditions: |
| 12 # |
| 13 # The above copyright notice and this permission notice shall be included |
| 14 # in all copies or substantial portions of the Software. |
| 15 # |
| 16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 17 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 18 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 19 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 20 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 22 # IN THE SOFTWARE. |
| 23 # |
| 24 import os |
| 25 from six.moves import configparser |
| 26 import requests |
| 27 import json |
| 28 |
| 29 |
| 30 class Credentials(object): |
| 31 """ |
| 32 Holds the credentials needed to authenticate requests. In addition |
| 33 the Credential object knows how to search for credentials and how |
| 34 to choose the right credentials when multiple credentials are found. |
| 35 """ |
| 36 |
| 37 def __init__(self, access_key=None, secret_key=None, token=None): |
| 38 self.access_key = access_key |
| 39 self.secret_key = secret_key |
| 40 self.token = token |
| 41 |
| 42 |
| 43 def _search_md(url='http://169.254.169.254/latest/meta-data/iam/'): |
| 44 d = {} |
| 45 try: |
| 46 r = requests.get(url, timeout=.1) |
| 47 if r.content: |
| 48 fields = r.content.split('\n') |
| 49 for field in fields: |
| 50 if field.endswith('/'): |
| 51 d[field[0:-1]] = get_iam_role(url + field) |
| 52 else: |
| 53 val = requests.get(url + field).content |
| 54 if val[0] == '{': |
| 55 val = json.loads(val) |
| 56 else: |
| 57 p = val.find('\n') |
| 58 if p > 0: |
| 59 val = r.content.split('\n') |
| 60 d[field] = val |
| 61 except (requests.Timeout, requests.ConnectionError): |
| 62 pass |
| 63 return d |
| 64 |
| 65 |
| 66 def search_metadata(**kwargs): |
| 67 credentials = None |
| 68 metadata = _search_md() |
| 69 # Assuming there's only one role on the instance profile. |
| 70 if metadata: |
| 71 metadata = metadata['iam']['security-credentials'].values()[0] |
| 72 credentials = Credentials(metadata['AccessKeyId'], |
| 73 metadata['SecretAccessKey'], |
| 74 metadata['Token']) |
| 75 return credentials |
| 76 |
| 77 |
| 78 def search_environment(**kwargs): |
| 79 """ |
| 80 Search for credentials in explicit environment variables. |
| 81 """ |
| 82 credentials = None |
| 83 access_key = os.environ.get(kwargs['access_key_name'].upper(), None) |
| 84 secret_key = os.environ.get(kwargs['secret_key_name'].upper(), None) |
| 85 if access_key and secret_key: |
| 86 credentials = Credentials(access_key, secret_key) |
| 87 return credentials |
| 88 |
| 89 |
| 90 def search_file(**kwargs): |
| 91 """ |
| 92 If the 'AWS_CREDENTIAL_FILE' environment variable exists, parse that |
| 93 file for credentials. |
| 94 """ |
| 95 credentials = None |
| 96 if 'AWS_CREDENTIAL_FILE' in os.environ: |
| 97 persona = kwargs.get('persona', 'default') |
| 98 access_key_name = kwargs['access_key_name'] |
| 99 secret_key_name = kwargs['secret_key_name'] |
| 100 access_key = secret_key = None |
| 101 path = os.getenv('AWS_CREDENTIAL_FILE') |
| 102 path = os.path.expandvars(path) |
| 103 path = os.path.expanduser(path) |
| 104 cp = configparser.RawConfigParser() |
| 105 cp.read(path) |
| 106 if not cp.has_section(persona): |
| 107 raise ValueError('Persona: %s not found' % persona) |
| 108 if cp.has_option(persona, access_key_name): |
| 109 access_key = cp.get(persona, access_key_name) |
| 110 else: |
| 111 access_key = None |
| 112 if cp.has_option(persona, secret_key_name): |
| 113 secret_key = cp.get(persona, secret_key_name) |
| 114 else: |
| 115 secret_key = None |
| 116 if access_key and secret_key: |
| 117 credentials = Credentials(access_key, secret_key) |
| 118 return credentials |
| 119 |
| 120 |
| 121 def search_boto_config(**kwargs): |
| 122 """ |
| 123 Look for credentials in boto config file. |
| 124 """ |
| 125 credentials = access_key = secret_key = None |
| 126 if 'BOTO_CONFIG' in os.environ: |
| 127 paths = [os.environ['BOTO_CONFIG']] |
| 128 else: |
| 129 paths = ['/etc/boto.cfg', '~/.boto'] |
| 130 paths = [os.path.expandvars(p) for p in paths] |
| 131 paths = [os.path.expanduser(p) for p in paths] |
| 132 cp = configparser.RawConfigParser() |
| 133 cp.read(paths) |
| 134 if cp.has_section('Credentials'): |
| 135 access_key = cp.get('Credentials', 'aws_access_key_id') |
| 136 secret_key = cp.get('Credentials', 'aws_secret_access_key') |
| 137 if access_key and secret_key: |
| 138 credentials = Credentials(access_key, secret_key) |
| 139 return credentials |
| 140 |
| 141 AllCredentialFunctions = [search_environment, |
| 142 search_file, |
| 143 search_boto_config, |
| 144 search_metadata] |
| 145 |
| 146 |
| 147 def get_credentials(persona='default'): |
| 148 for cred_fn in AllCredentialFunctions: |
| 149 credentials = cred_fn(persona=persona, |
| 150 access_key_name='access_key', |
| 151 secret_key_name='secret_key') |
| 152 if credentials: |
| 153 break |
| 154 return credentials |
OLD | NEW |