credentials.py 4.8 KB

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