providers.py 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. import calendar
  2. import configparser
  3. import json
  4. import os
  5. import time
  6. import requests
  7. from Tea.core import TeaCore
  8. from alibabacloud_credentials import credentials
  9. from alibabacloud_credentials.exceptions import CredentialException
  10. from alibabacloud_credentials.models import Config
  11. from alibabacloud_credentials.utils import auth_constant as ac
  12. from alibabacloud_credentials.utils import auth_util as au
  13. from alibabacloud_credentials.utils import parameter_helper as ph
  14. class AlibabaCloudCredentialsProvider:
  15. """BaseProvider class"""
  16. duration_seconds = 3600
  17. timeout = 3000
  18. def __init__(self, config=None):
  19. if isinstance(config, Config):
  20. self.type = config.type
  21. self.access_key_id = config.access_key_id
  22. self.access_key_secret = config.access_key_secret
  23. self.role_arn = config.role_arn
  24. self.role_session_name = config.role_session_name
  25. self.public_key_id = config.public_key_id
  26. self.role_name = config.role_name
  27. self.disable_imds_v1 = config.disable_imds_v1
  28. self.oidc_provider_arn = config.oidc_provider_arn
  29. self.oidc_token_file_path = config.oidc_token_file_path
  30. self.private_key_file = config.private_key_file
  31. self.bearer_token = config.bearer_token
  32. self.security_token = config.security_token
  33. self.host = config.host
  34. self.timeout = config.timeout or AlibabaCloudCredentialsProvider.timeout
  35. self.connect_timeout = config.connect_timeout or AlibabaCloudCredentialsProvider.timeout
  36. self.proxy = config.proxy
  37. self.sts_endpoint = config.sts_endpoint
  38. def _set_arg(self, key, value):
  39. if value is not None:
  40. setattr(self, key, value)
  41. val = getattr(self, key, None)
  42. if val is None:
  43. setattr(self, key, None)
  44. def _verify_empty_args(self, *args, config):
  45. if None in args and config is None:
  46. raise CredentialException(
  47. '"%s" needs to receive a "model.Config" object or other necessary args' % self.__class__
  48. )
  49. def get_credentials(self):
  50. raise NotImplementedError('get_credentials() must be overridden')
  51. class DefaultCredentialsProvider(AlibabaCloudCredentialsProvider):
  52. def __init__(self):
  53. super().__init__()
  54. self.user_configuration_providers = [
  55. EnvironmentVariableCredentialsProvider()
  56. ]
  57. if au.enable_oidc_credential:
  58. self.user_configuration_providers.append(OIDCRoleArnCredentialProvider(
  59. role_session_name=au.environment_role_session_name,
  60. role_arn=au.environment_role_arn,
  61. oidc_provider_arn=au.environment_oidc_provider_arn,
  62. oidc_token_file_path=au.environment_oidc_token_file
  63. ))
  64. self.user_configuration_providers.append(ProfileCredentialsProvider())
  65. role_name = au.environment_ECSMeta_data
  66. if role_name is not None:
  67. self.user_configuration_providers.append(EcsRamRoleCredentialProvider(role_name))
  68. self.user_configuration_providers.append(CredentialsUriProvider())
  69. def get_credentials(self):
  70. for provider in self.user_configuration_providers:
  71. credential = provider.get_credentials()
  72. if credential is not None:
  73. return credential
  74. raise CredentialException("not found credentials")
  75. def add_credentials_provider(self, p):
  76. self.user_configuration_providers.append(p)
  77. def remove_credentials_provider(self, p):
  78. self.user_configuration_providers.remove(p)
  79. def contains_credentials_provider(self, p):
  80. return self.user_configuration_providers.__contains__(p)
  81. def clear_credentials_provider(self):
  82. self.user_configuration_providers.clear()
  83. class EcsRamRoleCredentialProvider(AlibabaCloudCredentialsProvider):
  84. """EcsRamRoleCredentialProvider"""
  85. default_metadata_token_duration = 21600
  86. def __init__(self, role_name=None, config=None):
  87. self._verify_empty_args(role_name, config=config)
  88. super().__init__(config)
  89. self.__url_in_ecs_metadata = "/latest/meta-data/ram/security-credentials/"
  90. self.__url_in_ecs_metadata_token = "/latest/api/token"
  91. self.__ecs_metadata_fetch_error_msg = "Failed to get RAM session credentials from ECS metadata service."
  92. self.__ecs_metadata_token_fetch_error_msg = "Failed to get token from ECS Metadata Service."
  93. self.__metadata_service_host = "100.100.100.200"
  94. self._set_arg('role_name', role_name)
  95. self.disable_imds_v1 = au.environment_imds_v1_disabled and au.environment_imds_v1_disabled.lower() == 'true'
  96. if isinstance(config, Config):
  97. self.disable_imds_v1 = config.disable_imds_v1 is not None and config.disable_imds_v1 == True
  98. def _should_fallback_to_imds_v1(self, metadata_token):
  99. return metadata_token is not None and not self.disable_imds_v1
  100. def _new_get_request(self, pathname, url=None, metadata_token=None):
  101. tea_request = ph.get_new_request()
  102. tea_request.headers['host'] = url if url else self.__metadata_service_host
  103. if metadata_token:
  104. tea_request.headers['X-aliyun-ecs-metadata-token'] = metadata_token
  105. if not url:
  106. tea_request.pathname = pathname
  107. return tea_request
  108. def _get_role_name(self, url=None):
  109. metadata_token = self._get_metadata_token(url)
  110. try:
  111. self.role_name = self._do_get_role_name(url, metadata_token)
  112. except Exception:
  113. if self._should_fallback_to_imds_v1(metadata_token):
  114. self.role_name = self._do_get_role_name(url, None)
  115. else:
  116. raise
  117. async def _get_role_name_async(self, url=None):
  118. metadata_token = await self._get_metadata_token_async(url)
  119. try:
  120. self.role_name = await self._do_get_role_name_async(url, metadata_token)
  121. except Exception:
  122. if self._should_fallback_to_imds_v1(metadata_token):
  123. self.role_name = await self._do_get_role_name_async(url, None)
  124. else:
  125. raise
  126. def _do_get_role_name(self, url, metadata_token):
  127. tea_request = self._new_get_request(self.__url_in_ecs_metadata, url, metadata_token)
  128. response = TeaCore.do_action(tea_request)
  129. if response.status_code != 200:
  130. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  131. return response.body.decode('utf-8')
  132. async def _do_get_role_name_async(self, url, metadata_token):
  133. tea_request = self._new_get_request(self.__url_in_ecs_metadata, url, metadata_token)
  134. response = await TeaCore.async_do_action(tea_request)
  135. if response.status_code != 200:
  136. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  137. return response.body.decode('utf-8')
  138. def _get_metadata_token(self, url=None):
  139. tea_request = ph.get_new_request()
  140. tea_request.method = 'PUT'
  141. tea_request.headers['host'] = url if url else self.__metadata_service_host
  142. tea_request.headers['X-aliyun-ecs-metadata-token-ttl-seconds'] = str(self.default_metadata_token_duration)
  143. if not url:
  144. tea_request.pathname = self.__url_in_ecs_metadata_token
  145. try:
  146. response = TeaCore.do_action(tea_request)
  147. if response.status_code != 200:
  148. raise CredentialException(
  149. self.__ecs_metadata_token_fetch_error_msg + " HttpCode=" + str(response.status_code))
  150. return response.body.decode('utf-8')
  151. except Exception as e:
  152. if self.disable_imds_v1:
  153. raise e
  154. return None
  155. async def _get_metadata_token_async(self, url=None):
  156. tea_request = ph.get_new_request()
  157. tea_request.method = 'PUT'
  158. tea_request.headers['host'] = url if url else self.__metadata_service_host
  159. tea_request.headers['X-aliyun-ecs-metadata-token-ttl-seconds'] = str(self.default_metadata_token_duration)
  160. if not url:
  161. tea_request.pathname = self.__url_in_ecs_metadata_token
  162. try:
  163. response = await TeaCore.async_do_action(tea_request)
  164. if response.status_code != 200:
  165. raise CredentialException(
  166. self.__ecs_metadata_token_fetch_error_msg + " HttpCode=" + str(response.status_code))
  167. return response.body.decode('utf-8')
  168. except Exception as e:
  169. if self.disable_imds_v1:
  170. raise e
  171. return None
  172. def _create_credential(self, url=None):
  173. metadata_token = self._get_metadata_token(url)
  174. try:
  175. return self._do_create_credential(url, metadata_token)
  176. except Exception:
  177. if self._should_fallback_to_imds_v1(metadata_token):
  178. return self._do_create_credential(url, None)
  179. raise
  180. def _do_create_credential(self, url, metadata_token):
  181. tea_request = self._new_get_request(self.__url_in_ecs_metadata + self.role_name, url, metadata_token)
  182. response = TeaCore.do_action(tea_request)
  183. if response.status_code != 200:
  184. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  185. dic = json.loads(response.body.decode('utf-8'))
  186. content_code = dic.get('Code')
  187. content_access_key_id = dic.get('AccessKeyId')
  188. content_access_key_secret = dic.get('AccessKeySecret')
  189. content_security_token = dic.get('SecurityToken')
  190. content_expiration = dic.get('Expiration')
  191. if content_code != "Success":
  192. raise CredentialException(self.__ecs_metadata_fetch_error_msg)
  193. time_array = time.strptime(content_expiration, "%Y-%m-%dT%H:%M:%SZ")
  194. time_stamp = calendar.timegm(time_array)
  195. return credentials.EcsRamRoleCredential(content_access_key_id, content_access_key_secret,
  196. content_security_token, time_stamp, self)
  197. def get_credentials(self):
  198. if self.role_name == "":
  199. self._get_role_name()
  200. return self._create_credential()
  201. async def _create_credential_async(self, url=None):
  202. metadata_token = await self._get_metadata_token_async(url)
  203. try:
  204. return await self._do_create_credential_async(url, metadata_token)
  205. except Exception:
  206. if self._should_fallback_to_imds_v1(metadata_token):
  207. return await self._do_create_credential_async(url, None)
  208. raise
  209. async def _do_create_credential_async(self, url, metadata_token):
  210. tea_request = self._new_get_request(self.__url_in_ecs_metadata + self.role_name, url, metadata_token)
  211. response = await TeaCore.async_do_action(tea_request)
  212. if response.status_code != 200:
  213. raise CredentialException(self.__ecs_metadata_fetch_error_msg + " HttpCode=" + str(response.status_code))
  214. dic = json.loads(response.body.decode('utf-8'))
  215. content_code = dic.get('Code')
  216. content_access_key_id = dic.get('AccessKeyId')
  217. content_access_key_secret = dic.get('AccessKeySecret')
  218. content_security_token = dic.get('SecurityToken')
  219. content_expiration = dic.get('Expiration')
  220. if content_code != "Success":
  221. raise CredentialException(self.__ecs_metadata_fetch_error_msg)
  222. time_array = time.strptime(content_expiration, "%Y-%m-%dT%H:%M:%SZ")
  223. time_stamp = calendar.timegm(time_array)
  224. return credentials.EcsRamRoleCredential(content_access_key_id, content_access_key_secret,
  225. content_security_token, time_stamp, self)
  226. async def get_credentials_async(self):
  227. if self.role_name == "":
  228. await self._get_role_name_async()
  229. return await self._create_credential_async()
  230. class RamRoleArnCredentialProvider(AlibabaCloudCredentialsProvider):
  231. """RamRoleArnCredentialProvider"""
  232. def __init__(self, access_key_id=None, access_key_secret=None, role_session_name=None, role_arn=None,
  233. region_id=None,
  234. policy=None, config=None):
  235. self._verify_empty_args(access_key_id, access_key_secret, config=config)
  236. super().__init__(config)
  237. self._set_arg('role_arn', role_arn)
  238. self._set_arg('access_key_id', access_key_id)
  239. self._set_arg('access_key_secret', access_key_secret)
  240. self._set_arg('region_id', region_id)
  241. self._set_arg('role_session_name', role_session_name)
  242. self._set_arg('policy', policy)
  243. if region_id is None and au.environment_sts_region is not None:
  244. self._set_arg('region_id', au.environment_sts_region)
  245. if self.region_id is not None:
  246. self._set_arg('sts_endpoint', f'sts.{self.region_id}.aliyuncs.com')
  247. else:
  248. self._set_arg('sts_endpoint',
  249. 'sts.aliyuncs.com' if config is None or config.sts_endpoint is None else config.sts_endpoint)
  250. def get_credentials(self):
  251. return self._create_credentials()
  252. def _create_credentials(self):
  253. # 获取credential 先实现签名用工具类
  254. tea_request = ph.get_new_request()
  255. tea_request.query = {
  256. 'Action': 'AssumeRole',
  257. 'Format': 'JSON',
  258. 'Version': '2015-04-01',
  259. 'DurationSeconds': str(self.duration_seconds),
  260. 'RoleArn': self.role_arn,
  261. 'AccessKeyId': self.access_key_id,
  262. 'RoleSessionName': self.role_session_name,
  263. 'SignatureMethod': 'HMAC-SHA1',
  264. 'SignatureVersion': '1.0'
  265. }
  266. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  267. tea_request.query["SignatureNonce"] = ph.get_uuid()
  268. if self.policy is not None:
  269. tea_request.query["Policy"] = self.policy
  270. string_to_sign = ph.compose_string_to_sign("GET", tea_request.query)
  271. signature = ph.sign_string(string_to_sign, self.access_key_secret + "&")
  272. tea_request.query["Signature"] = signature
  273. tea_request.protocol = 'https'
  274. tea_request.headers['host'] = self.sts_endpoint
  275. # request
  276. response = TeaCore.do_action(tea_request)
  277. if response.status_code == 200:
  278. dic = json.loads(response.body.decode('utf-8'))
  279. if "Credentials" in dic:
  280. cre = dic.get("Credentials")
  281. # 先转换为时间数组
  282. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  283. # 转换为时间戳
  284. expiration = calendar.timegm(time_array)
  285. return credentials.RamRoleArnCredential(cre.get("AccessKeyId"), cre.get("AccessKeySecret"),
  286. cre.get("SecurityToken"), expiration, self)
  287. raise CredentialException(response.body.decode('utf-8'))
  288. async def get_credentials_async(self):
  289. return await self._create_credentials_async()
  290. async def _create_credentials_async(self):
  291. # 获取credential 先实现签名用工具类
  292. tea_request = ph.get_new_request()
  293. tea_request.query = {
  294. 'Action': 'AssumeRole',
  295. 'Format': 'JSON',
  296. 'Version': '2015-04-01',
  297. 'DurationSeconds': str(self.duration_seconds),
  298. 'RoleArn': self.role_arn,
  299. 'AccessKeyId': self.access_key_id,
  300. 'RoleSessionName': self.role_session_name,
  301. 'SignatureMethod': 'HMAC-SHA1',
  302. 'SignatureVersion': '1.0'
  303. }
  304. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  305. tea_request.query["SignatureNonce"] = ph.get_uuid()
  306. if self.policy is not None:
  307. tea_request.query["Policy"] = self.policy
  308. string_to_sign = ph.compose_string_to_sign("GET", tea_request.query)
  309. signature = ph.sign_string(string_to_sign, self.access_key_secret + "&")
  310. tea_request.query["Signature"] = signature
  311. tea_request.protocol = 'https'
  312. tea_request.headers['host'] = self.sts_endpoint
  313. # request
  314. response = await TeaCore.async_do_action(tea_request)
  315. if response.status_code == 200:
  316. dic = json.loads(response.body.decode('utf-8'))
  317. if "Credentials" in dic:
  318. cre = dic.get("Credentials")
  319. # 先转换为时间数组
  320. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  321. # 转换为时间戳
  322. expiration = calendar.timegm(time_array)
  323. return credentials.RamRoleArnCredential(cre.get("AccessKeyId"), cre.get("AccessKeySecret"),
  324. cre.get("SecurityToken"), expiration, self)
  325. raise CredentialException(response.body.decode('utf-8'))
  326. class OIDCRoleArnCredentialProvider(AlibabaCloudCredentialsProvider):
  327. """OIDCRoleArnCredentialProvider"""
  328. def __init__(self, role_session_name=None, role_arn=None,
  329. oidc_provider_arn=None,
  330. oidc_token_file_path=None,
  331. region_id=None,
  332. policy=None, config=None):
  333. self._verify_empty_args(role_arn, oidc_provider_arn, oidc_token_file_path, config=config)
  334. super().__init__(config)
  335. self._set_arg('role_arn', role_arn)
  336. self._set_arg('oidc_provider_arn', oidc_provider_arn)
  337. if oidc_token_file_path is not None:
  338. self._set_arg('oidc_token_file_path', oidc_token_file_path)
  339. elif config.oidc_token_file_path is not None:
  340. self._set_arg('oidc_token_file_path', oidc_token_file_path)
  341. elif au.environment_oidc_token_file is not None:
  342. self._set_arg('oidc_token_file_path', au.environment_oidc_token_file)
  343. else:
  344. raise CredentialException(
  345. 'The oidc_token_file_path does not exist and env ALIBABA_CLOUD_OIDC_TOKEN_FILE is none.')
  346. self._set_arg('region_id', region_id)
  347. self._set_arg('role_session_name', role_session_name)
  348. self._set_arg('policy', policy)
  349. if region_id is None and au.environment_sts_region is not None:
  350. self._set_arg('region_id', au.environment_sts_region)
  351. if self.region_id is not None:
  352. self._set_arg('sts_endpoint', f'sts.{self.region_id}.aliyuncs.com')
  353. else:
  354. self._set_arg('sts_endpoint',
  355. 'sts.aliyuncs.com' if config is None or config.sts_endpoint is None else config.sts_endpoint)
  356. def get_credentials(self):
  357. return self._create_credentials()
  358. def _create_credentials(self):
  359. # 获取credential 先实现签名用工具类
  360. oidc_token = au.get_private_key(self.oidc_token_file_path)
  361. tea_request = ph.get_new_request()
  362. tea_request.query = {
  363. 'Action': 'AssumeRoleWithOIDC',
  364. 'Format': 'JSON',
  365. 'Version': '2015-04-01',
  366. 'DurationSeconds': str(self.duration_seconds),
  367. 'RoleArn': self.role_arn,
  368. 'OIDCProviderArn': self.oidc_provider_arn,
  369. 'OIDCToken': oidc_token,
  370. 'RoleSessionName': self.role_session_name or 'defaultSessionName'
  371. }
  372. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  373. tea_request.query["SignatureNonce"] = ph.get_uuid()
  374. if self.policy is not None:
  375. tea_request.query["Policy"] = self.policy
  376. tea_request.protocol = 'https'
  377. tea_request.headers['host'] = self.sts_endpoint
  378. # request
  379. response = TeaCore.do_action(tea_request)
  380. if response.status_code == 200:
  381. dic = json.loads(response.body.decode('utf-8'))
  382. if "Credentials" in dic:
  383. cre = dic.get("Credentials")
  384. # 先转换为时间数组
  385. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  386. # 转换为时间戳
  387. expiration = calendar.timegm(time_array)
  388. return credentials.OIDCRoleArnCredential(cre.get("AccessKeyId"), cre.get("AccessKeySecret"),
  389. cre.get("SecurityToken"), expiration, self)
  390. raise CredentialException(response.body.decode('utf-8'))
  391. async def get_credentials_async(self):
  392. return await self._create_credentials_async()
  393. async def _create_credentials_async(self):
  394. # 获取credential 先实现签名用工具类
  395. oidc_token = au.get_private_key(self.oidc_token_file_path)
  396. tea_request = ph.get_new_request()
  397. tea_request.query = {
  398. 'Action': 'AssumeRoleWithOIDC',
  399. 'Format': 'JSON',
  400. 'Version': '2015-04-01',
  401. 'DurationSeconds': str(self.duration_seconds),
  402. 'RoleArn': self.role_arn,
  403. 'OIDCProviderArn': self.oidc_provider_arn,
  404. 'OIDCToken': oidc_token,
  405. 'RoleSessionName': self.role_session_name or 'defaultSessionName'
  406. }
  407. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  408. tea_request.query["SignatureNonce"] = ph.get_uuid()
  409. if self.policy is not None:
  410. tea_request.query["Policy"] = self.policy
  411. tea_request.protocol = 'https'
  412. tea_request.headers['host'] = self.sts_endpoint
  413. # request
  414. response = await TeaCore.async_do_action(tea_request)
  415. if response.status_code == 200:
  416. dic = json.loads(response.body.decode('utf-8'))
  417. if "Credentials" in dic:
  418. cre = dic.get("Credentials")
  419. # 先转换为时间数组
  420. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  421. # 转换为时间戳
  422. expiration = calendar.timegm(time_array)
  423. return credentials.OIDCRoleArnCredential(cre.get("AccessKeyId"), cre.get("AccessKeySecret"),
  424. cre.get("SecurityToken"), expiration, self)
  425. raise CredentialException(response.body.decode('utf-8'))
  426. class RsaKeyPairCredentialProvider(AlibabaCloudCredentialsProvider):
  427. def __init__(self, access_key_id=None, access_key_secret=None, region_id=None, config=None):
  428. self._verify_empty_args(access_key_id, access_key_secret, config=config)
  429. super().__init__(config)
  430. self._set_arg('access_key_id', access_key_id)
  431. self._set_arg('access_key_secret', access_key_secret)
  432. self._set_arg('region_id', region_id)
  433. async def get_credentials_async(self):
  434. return await self._create_credential_async()
  435. async def _create_credential_async(self, turl=None):
  436. tea_request = ph.get_new_request()
  437. tea_request.query = {
  438. 'Action': 'GenerateSessionAccessKey',
  439. 'Format': 'JSON',
  440. 'Version': '2015-04-01',
  441. 'DurationSeconds': str(self.duration_seconds),
  442. 'AccessKeyId': self.access_key_id,
  443. 'SignatureMethod': 'HMAC-SHA1',
  444. 'SignatureVersion': '1.0'
  445. }
  446. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  447. tea_request.query["SignatureNonce"] = ph.get_uuid()
  448. str_to_sign = ph.compose_string_to_sign('GET', tea_request.query)
  449. signature = ph.sign_string(str_to_sign, self.access_key_id + '&')
  450. tea_request.query['Signature'] = signature
  451. tea_request.protocol = 'https'
  452. tea_request.headers['host'] = turl if turl else 'sts.aliyuncs.com'
  453. # request
  454. response = await TeaCore.async_do_action(tea_request)
  455. if response.status_code == 200:
  456. dic = json.loads(response.body.decode('utf-8'))
  457. if "SessionAccessKey" in dic:
  458. cre = dic.get("SessionAccessKey")
  459. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  460. expiration = calendar.timegm(time_array)
  461. return credentials.RsaKeyPairCredential(cre.get("SessionAccessKeyId"),
  462. cre.get("SessionAccessKeySecret"),
  463. expiration, self)
  464. raise CredentialException(response.body.decode('utf-8'))
  465. def get_credentials(self):
  466. return self._create_credential()
  467. def _create_credential(self, turl=None):
  468. tea_request = ph.get_new_request()
  469. tea_request.query = {
  470. 'Action': 'GenerateSessionAccessKey',
  471. 'Format': 'JSON',
  472. 'Version': '2015-04-01',
  473. 'DurationSeconds': str(self.duration_seconds),
  474. 'AccessKeyId': self.access_key_id,
  475. 'SignatureMethod': 'HMAC-SHA1',
  476. 'SignatureVersion': '1.0'
  477. }
  478. tea_request.query["Timestamp"] = ph.get_iso_8061_date()
  479. tea_request.query["SignatureNonce"] = ph.get_uuid()
  480. str_to_sign = ph.compose_string_to_sign('GET', tea_request.query)
  481. signature = ph.sign_string(str_to_sign, self.access_key_id + '&')
  482. tea_request.query['Signature'] = signature
  483. tea_request.protocol = 'https'
  484. tea_request.headers['host'] = turl if turl else 'sts.aliyuncs.com'
  485. # request
  486. response = TeaCore.do_action(tea_request)
  487. if response.status_code == 200:
  488. dic = json.loads(response.body.decode('utf-8'))
  489. if "SessionAccessKey" in dic:
  490. cre = dic.get("SessionAccessKey")
  491. time_array = time.strptime(cre.get("Expiration"), "%Y-%m-%dT%H:%M:%SZ")
  492. expiration = calendar.timegm(time_array)
  493. return credentials.RsaKeyPairCredential(cre.get("SessionAccessKeyId"),
  494. cre.get("SessionAccessKeySecret"),
  495. expiration, self)
  496. raise CredentialException(response.body.decode('utf-8'))
  497. class ProfileCredentialsProvider(AlibabaCloudCredentialsProvider):
  498. def __init__(self, path=None):
  499. super().__init__()
  500. self._set_arg('file_path', path)
  501. def parse_ini(self):
  502. file_path = self.file_path if self.file_path else au.environment_credentials_file
  503. if file_path is None:
  504. if not ac.HOME:
  505. return
  506. if os.path.exists(os.path.join(ac.HOME, "/.alibabacloud/credentials.ini")):
  507. # Support '/.alibabacloud/credentials.ini' is due to historical mistakes.
  508. # Please try to use '~/.alibabacloud/credentials.ini'.
  509. file_path = os.path.join(ac.HOME, "/.alibabacloud/credentials.ini")
  510. elif os.path.exists(os.path.join(ac.HOME, ".alibabacloud/credentials.ini")):
  511. file_path = os.path.join(ac.HOME, ".alibabacloud/credentials.ini")
  512. if file_path is None:
  513. return
  514. elif len(file_path) == 0:
  515. raise CredentialException("The specified credentials file is empty")
  516. # loads ini
  517. conf = configparser.ConfigParser()
  518. conf.read(file_path, encoding='utf-8')
  519. ini_map = dict(conf._sections)
  520. for k in dict(conf._sections):
  521. option = dict(ini_map[k])
  522. for key, value in dict(ini_map[k]).items():
  523. if '#' in value:
  524. option[key] = value.split('#')[0].strip()
  525. else:
  526. option[key] = value.strip()
  527. ini_map[k] = option
  528. client_config = ini_map.get(au.client_type)
  529. return client_config
  530. def get_credentials(self):
  531. client_config = self.parse_ini()
  532. if client_config is None:
  533. return
  534. return self._create_credential(client_config)
  535. def _create_credential(self, config):
  536. config_type = config.get(ac.INI_TYPE)
  537. if not config_type:
  538. raise CredentialException("The configured client type is empty")
  539. elif ac.INI_TYPE_ARN == config_type:
  540. return self._get_sts_assume_role_session_provider(config).get_credentials()
  541. elif ac.INI_TYPE_OIDC == config_type:
  542. return self._get_sts_oidc_role_session_provider(config).get_credentials()
  543. elif ac.INI_TYPE_KEY_PAIR == config_type:
  544. return self._get_sts_get_session_access_key_provider(config).get_credentials()
  545. elif ac.INI_TYPE_RAM == config_type:
  546. return self._get_instance_profile_provider(config).get_credentials()
  547. access_key_id = config.get(ac.INI_ACCESS_KEY_ID)
  548. access_key_secret = config.get(ac.INI_ACCESS_KEY_IDSECRET)
  549. if not access_key_id or not access_key_secret:
  550. return
  551. return credentials.AccessKeyCredential(access_key_id, access_key_secret)
  552. @staticmethod
  553. def _get_sts_assume_role_session_provider(config):
  554. access_key_id = config.get(ac.INI_ACCESS_KEY_ID)
  555. access_key_secret = config.get(ac.INI_ACCESS_KEY_IDSECRET)
  556. role_session_name = config.get(ac.INI_ROLE_SESSION_NAME)
  557. role_arn = config.get(ac.INI_ROLE_ARN)
  558. region_id = config.get(ac.DEFAULT_REGION)
  559. policy = config.get(ac.INI_POLICY)
  560. if not access_key_id or not access_key_secret:
  561. raise CredentialException("The configured access_key_id or access_key_secret is empty")
  562. if not role_session_name or not role_arn:
  563. raise CredentialException("The configured role_session_name or role_arn is empty")
  564. return RamRoleArnCredentialProvider(
  565. access_key_id, access_key_secret, role_session_name, role_arn, region_id, policy
  566. )
  567. @staticmethod
  568. def _get_sts_oidc_role_session_provider(config):
  569. role_session_name = config.get(ac.INI_ROLE_SESSION_NAME)
  570. role_arn = config.get(ac.INI_ROLE_ARN)
  571. oidc_provider_arn = config.get(ac.INI_OIDC_PROVIDER_ARN)
  572. oidc_token_file_path = config.get(ac.INI_OIDC_TOKEN_FILE_PATH)
  573. region_id = config.get(ac.DEFAULT_REGION)
  574. policy = config.get(ac.INI_POLICY)
  575. if not role_arn:
  576. raise CredentialException("The configured role_arn is empty")
  577. if not oidc_provider_arn:
  578. raise CredentialException("The configured oidc_provider_arn is empty")
  579. return OIDCRoleArnCredentialProvider(
  580. role_session_name, role_arn, oidc_provider_arn, oidc_token_file_path,
  581. region_id, policy
  582. )
  583. @staticmethod
  584. def _get_sts_get_session_access_key_provider(config):
  585. public_key_id = config.get(ac.INI_PUBLIC_KEY_ID)
  586. private_key_file = config.get(ac.INI_PRIVATE_KEY_FILE)
  587. if not private_key_file:
  588. raise CredentialException("The configured private_key_file is empty")
  589. private_key = au.get_private_key(private_key_file)
  590. if not public_key_id or not private_key:
  591. raise CredentialException("The configured public_key_id or private_key_file content is empty")
  592. return RsaKeyPairCredentialProvider(public_key_id, private_key)
  593. @staticmethod
  594. def _get_instance_profile_provider(config):
  595. role_name = config.get(ac.INI_ROLE_NAME)
  596. if not role_name:
  597. raise CredentialException("The configured role_name is empty")
  598. return EcsRamRoleCredentialProvider(role_name)
  599. class EnvironmentVariableCredentialsProvider(AlibabaCloudCredentialsProvider):
  600. def get_credentials(self):
  601. if 'default' != au.client_type:
  602. return
  603. access_key_id = au.environment_access_key_id
  604. access_key_secret = au.environment_access_key_secret
  605. security_token = au.environment_security_token
  606. if access_key_id is None or access_key_secret is None:
  607. return
  608. if len(access_key_id) == 0:
  609. raise CredentialException("Environment variable accessKeyId cannot be empty")
  610. if len(access_key_secret) == 0:
  611. raise CredentialException("Environment variable accessKeySecret cannot be empty")
  612. if security_token is not None and len(security_token) > 0:
  613. return credentials.StsCredential(access_key_id, access_key_secret, security_token)
  614. return credentials.AccessKeyCredential(access_key_id, access_key_secret)
  615. class CredentialsUriProvider(AlibabaCloudCredentialsProvider):
  616. def get_credentials(self):
  617. credentials_uri = os.environ.get('ALIBABA_CLOUD_CREDENTIALS_URI')
  618. if credentials_uri is None:
  619. return None
  620. return credentials.CredentialsURICredential(credentials_uri)