Add support for IAM roles and temp tokens
Michal Ludvig authored on 2013/03/04 07:32:50... | ... |
@@ -534,6 +534,10 @@ class CloudFront(object): |
534 | 534 |
if not headers.has_key("x-amz-date"): |
535 | 535 |
headers["x-amz-date"] = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()) |
536 | 536 |
|
537 |
+ if len(self.config.access_token)>0: |
|
538 |
+ self.config.refresh_role() |
|
539 |
+ headers['x-amz-security-token']=self.config.access_token |
|
540 |
+ |
|
537 | 541 |
signature = self.sign_request(headers) |
538 | 542 |
headers["Authorization"] = "AWS "+self.config.access_key+":"+signature |
539 | 543 |
|
... | ... |
@@ -7,8 +7,11 @@ import logging |
7 | 7 |
from logging import debug, info, warning, error |
8 | 8 |
import re |
9 | 9 |
import os |
10 |
+import sys |
|
10 | 11 |
import Progress |
11 | 12 |
from SortedDict import SortedDict |
13 |
+import httplib |
|
14 |
+import json |
|
12 | 15 |
|
13 | 16 |
class Config(object): |
14 | 17 |
_instance = None |
... | ... |
@@ -16,6 +19,7 @@ class Config(object): |
16 | 16 |
_doc = {} |
17 | 17 |
access_key = "" |
18 | 18 |
secret_key = "" |
19 |
+ access_token = "" |
|
19 | 20 |
host_base = "s3.amazonaws.com" |
20 | 21 |
host_bucket = "%(bucket)s.s3.amazonaws.com" |
21 | 22 |
simpledb_host = "sdb.amazonaws.com" |
... | ... |
@@ -103,7 +107,73 @@ class Config(object): |
103 | 103 |
|
104 | 104 |
def __init__(self, configfile = None): |
105 | 105 |
if configfile: |
106 |
- self.read_config_file(configfile) |
|
106 |
+ try: |
|
107 |
+ self.read_config_file(configfile) |
|
108 |
+ except IOError, e: |
|
109 |
+ if 'AWS_CREDENTIAL_FILE' in os.environ: |
|
110 |
+ self.env_config() |
|
111 |
+ if len(self.access_key)==0: |
|
112 |
+ self.role_config() |
|
113 |
+ |
|
114 |
+ def role_config(self): |
|
115 |
+ conn = httplib.HTTPConnection(host='169.254.169.254',timeout=0.1) |
|
116 |
+ try: |
|
117 |
+ conn.request('GET', "/latest/meta-data/iam/security-credentials/") |
|
118 |
+ resp = conn.getresponse() |
|
119 |
+ files = resp.read() |
|
120 |
+ if resp.status == 200 and len(files)>1: |
|
121 |
+ conn.request('GET', "/latest/meta-data/iam/security-credentials/%s"%files) |
|
122 |
+ resp=conn.getresponse() |
|
123 |
+ if resp.status == 200: |
|
124 |
+ creds=json.load(resp) |
|
125 |
+ Config().update_option('access_key', creds['AccessKeyId'].encode('ascii')) |
|
126 |
+ Config().update_option('secret_key', creds['SecretAccessKey'].encode('ascii')) |
|
127 |
+ Config().update_option('access_token', creds['Token'].encode('ascii')) |
|
128 |
+ else: |
|
129 |
+ raise IOError |
|
130 |
+ else: |
|
131 |
+ raise IOError |
|
132 |
+ except: |
|
133 |
+ raise |
|
134 |
+ |
|
135 |
+ def role_refresh(self): |
|
136 |
+ try: |
|
137 |
+ self.role_config() |
|
138 |
+ except: |
|
139 |
+ warning("Could not refresh role") |
|
140 |
+ |
|
141 |
+ def env_config(self): |
|
142 |
+ cred_content = "" |
|
143 |
+ try: |
|
144 |
+ cred_file = open(os.environ['AWS_CREDENTIAL_FILE'],'r') |
|
145 |
+ cred_content = cred_file.read() |
|
146 |
+ except IOError, e: |
|
147 |
+ debug("Error %d accessing credentials file %s" % (e.errno,os.environ['AWS_CREDENTIAL_FILE'])) |
|
148 |
+ r_data = re.compile("^\s*(?P<orig_key>\w+)\s*=\s*(?P<value>.*)") |
|
149 |
+ r_quotes = re.compile("^\"(.*)\"\s*$") |
|
150 |
+ if len(cred_content)>0: |
|
151 |
+ for line in cred_content.splitlines(): |
|
152 |
+ is_data = r_data.match(line) |
|
153 |
+ is_data = r_data.match(line) |
|
154 |
+ if is_data: |
|
155 |
+ data = is_data.groupdict() |
|
156 |
+ if r_quotes.match(data["value"]): |
|
157 |
+ data["value"] = data["value"][1:-1] |
|
158 |
+ if data["orig_key"]=="AWSAccessKeyId": |
|
159 |
+ data["key"] = "access_key" |
|
160 |
+ elif data["orig_key"]=="AWSSecretKey": |
|
161 |
+ data["key"] = "secret_key" |
|
162 |
+ else: |
|
163 |
+ del data["key"] |
|
164 |
+ if "key" in data: |
|
165 |
+ Config().update_option(data["key"], data["value"]) |
|
166 |
+ if data["key"] in ("access_key", "secret_key", "gpg_passphrase"): |
|
167 |
+ print_value = (data["value"][:2]+"...%d_chars..."+data["value"][-1:]) % (len(data["value"]) - 3) |
|
168 |
+ else: |
|
169 |
+ print_value = data["value"] |
|
170 |
+ debug("env_Config: %s->%s" % (data["key"], print_value)) |
|
171 |
+ |
|
172 |
+ |
|
107 | 173 |
|
108 | 174 |
def option_list(self): |
109 | 175 |
retval = [] |
... | ... |
@@ -92,6 +92,9 @@ class S3Request(object): |
92 | 92 |
# Add in any extra headers from s3 config object |
93 | 93 |
if self.s3.config.extra_headers: |
94 | 94 |
self.headers.update(self.s3.config.extra_headers) |
95 |
+ if len(self.s3.config.access_token)>0: |
|
96 |
+ self.s3.config.role_refresh() |
|
97 |
+ self.headers['x-amz-security-token']=self.s3.config.access_token |
|
95 | 98 |
self.resource = resource |
96 | 99 |
self.method_string = method_string |
97 | 100 |
self.params = params |
... | ... |
@@ -131,6 +131,9 @@ class SimpleDB(object): |
131 | 131 |
def create_request(self, Action, DomainName, parameters = None): |
132 | 132 |
if not parameters: |
133 | 133 |
parameters = SortedDict() |
134 |
+ if len(self.config.access_token) > 0: |
|
135 |
+ self.config.refresh_role() |
|
136 |
+ parameters['Signature']=self.config.access_token |
|
134 | 137 |
parameters['AWSAccessKeyId'] = self.config.access_key |
135 | 138 |
parameters['Version'] = self.Version |
136 | 139 |
parameters['SignatureVersion'] = self.SignatureVersion |