credentials.py
4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# -*- coding: utf-8 -*-
import time
import requests
import json
import logging
import threading
from .exceptions import ClientError
from .utils import to_unixtime
from .compat import to_unicode
logger = logging.getLogger(__name__)
class Credentials(object):
def __init__(self, access_key_id="", access_key_secret="", security_token=""):
self.access_key_id = access_key_id
self.access_key_secret = access_key_secret
self.security_token = security_token
def get_access_key_id(self):
return self.access_key_id
def get_access_key_secret(self):
return self.access_key_secret
def get_security_token(self):
return self.security_token
DEFAULT_ECS_SESSION_TOKEN_DURATION_SECONDS = 3600 * 6
DEFAULT_ECS_SESSION_EXPIRED_FACTOR = 0.85
class EcsRamRoleCredential(Credentials):
def __init__(self,
access_key_id,
access_key_secret,
security_token,
expiration,
duration,
expired_factor=None):
self.access_key_id = access_key_id
self.access_key_secret = access_key_secret
self.security_token = security_token
self.expiration = expiration
self.duration = duration
self.expired_factor = expired_factor or DEFAULT_ECS_SESSION_EXPIRED_FACTOR
def get_access_key_id(self):
return self.access_key_id
def get_access_key_secret(self):
return self.access_key_secret
def get_security_token(self):
return self.security_token
def will_soon_expire(self):
now = int(time.time())
return self.duration * (1.0 - self.expired_factor) > self.expiration - now
class CredentialsProvider(object):
def get_credentials(self):
return
class StaticCredentialsProvider(CredentialsProvider):
def __init__(self, access_key_id="", access_key_secret="", security_token=""):
self.credentials = Credentials(access_key_id, access_key_secret, security_token)
def get_credentials(self):
return self.credentials
class EcsRamRoleCredentialsProvider(CredentialsProvider):
def __init__(self, auth_host, max_retries=3, timeout=10):
self.fetcher = EcsRamRoleCredentialsFetcher(auth_host)
self.max_retries = max_retries
self.timeout = timeout
self.credentials = None
self.__lock = threading.Lock()
def get_credentials(self):
if self.credentials is None or self.credentials.will_soon_expire():
with self.__lock:
if self.credentials is None or self.credentials.will_soon_expire():
try:
self.credentials = self.fetcher.fetch(self.max_retries, self.timeout)
except Exception as e:
logger.error("Exception: {0}".format(e))
if self.credentials is None:
raise
return self.credentials
class EcsRamRoleCredentialsFetcher(object):
def __init__(self, auth_host):
self.auth_host = auth_host
def fetch(self, retry_times=3, timeout=10):
for i in range(0, retry_times):
try:
response = requests.get(self.auth_host, timeout=timeout)
if response.status_code != 200:
raise ClientError(
"Failed to fetch credentials url, http code:{0}, msg:{1}".format(response.status_code,
response.text))
dic = json.loads(to_unicode(response.content))
code = dic.get('Code')
access_key_id = dic.get('AccessKeyId')
access_key_secret = dic.get('AccessKeySecret')
security_token = dic.get('SecurityToken')
expiration_date = dic.get('Expiration')
last_updated_date = dic.get('LastUpdated')
if code != "Success":
raise ClientError("Get credentials from ECS metadata service error, code: {0}".format(code))
expiration_stamp = to_unixtime(expiration_date, "%Y-%m-%dT%H:%M:%SZ")
duration = DEFAULT_ECS_SESSION_TOKEN_DURATION_SECONDS
if last_updated_date is not None:
last_updated_stamp = to_unixtime(last_updated_date, "%Y-%m-%dT%H:%M:%SZ")
duration = expiration_stamp - last_updated_stamp
return EcsRamRoleCredential(access_key_id, access_key_secret, security_token, expiration_stamp,
duration, DEFAULT_ECS_SESSION_EXPIRED_FACTOR)
except Exception as e:
if i == retry_times - 1:
logger.error("Exception: {0}".format(e))
raise ClientError("Failed to get credentials from ECS metadata service. {0}".format(e))