credentials.py 5.5 KB

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