credentials_provider_default_chain.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/auth/credentials.h>
  6. #include <aws/auth/private/credentials_utils.h>
  7. #include <aws/common/clock.h>
  8. #include <aws/common/environment.h>
  9. #include <aws/common/logging.h>
  10. #include <aws/common/string.h>
  11. #include <aws/io/tls_channel_handler.h>
  12. #include <aws/io/uri.h>
  13. #define DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS (15 * 60 * 1000)
  14. #if defined(_MSC_VER)
  15. # pragma warning(disable : 4204)
  16. /*
  17. * For designated initialization: .providers = providers,
  18. * of aws_credentials_provider_chain_options in function
  19. * aws_credentials_provider_new_chain_default
  20. */
  21. # pragma warning(disable : 4221)
  22. #endif /* _MSC_VER */
  23. AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_relative_uri, "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI");
  24. AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_full_uri, "AWS_CONTAINER_CREDENTIALS_FULL_URI");
  25. AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_token, "AWS_CONTAINER_AUTHORIZATION_TOKEN");
  26. AWS_STATIC_STRING_FROM_LITERAL(s_ecs_host, "169.254.170.2");
  27. AWS_STATIC_STRING_FROM_LITERAL(s_ec2_creds_env_disable, "AWS_EC2_METADATA_DISABLED");
  28. /**
  29. * ECS and IMDS credentials providers are mutually exclusive,
  30. * ECS has higher priority
  31. */
  32. static struct aws_credentials_provider *s_aws_credentials_provider_new_ecs_or_imds(
  33. struct aws_allocator *allocator,
  34. const struct aws_credentials_provider_shutdown_options *shutdown_options,
  35. struct aws_client_bootstrap *bootstrap,
  36. struct aws_tls_ctx *tls_ctx) {
  37. struct aws_byte_cursor auth_token_cursor;
  38. AWS_ZERO_STRUCT(auth_token_cursor);
  39. struct aws_credentials_provider *ecs_or_imds_provider = NULL;
  40. struct aws_string *ecs_relative_uri = NULL;
  41. struct aws_string *ecs_full_uri = NULL;
  42. struct aws_string *ec2_imds_disable = NULL;
  43. struct aws_string *ecs_token = NULL;
  44. if (aws_get_environment_value(allocator, s_ecs_creds_env_relative_uri, &ecs_relative_uri) != AWS_OP_SUCCESS ||
  45. aws_get_environment_value(allocator, s_ecs_creds_env_full_uri, &ecs_full_uri) != AWS_OP_SUCCESS ||
  46. aws_get_environment_value(allocator, s_ec2_creds_env_disable, &ec2_imds_disable) != AWS_OP_SUCCESS ||
  47. aws_get_environment_value(allocator, s_ecs_creds_env_token, &ecs_token) != AWS_OP_SUCCESS) {
  48. AWS_LOGF_ERROR(
  49. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  50. "Failed reading environment variables during default credentials provider chain initialization.");
  51. goto clean_up;
  52. }
  53. if (ecs_token && ecs_token->len) {
  54. auth_token_cursor = aws_byte_cursor_from_string(ecs_token);
  55. }
  56. /*
  57. * ToDo: the uri choice logic should be done in the ecs provider init logic. As it stands, it's a nightmare
  58. * to try and use the ecs provider anywhere outside the default chain.
  59. */
  60. if (ecs_relative_uri && ecs_relative_uri->len) {
  61. struct aws_credentials_provider_ecs_options ecs_options = {
  62. .shutdown_options = *shutdown_options,
  63. .bootstrap = bootstrap,
  64. .host = aws_byte_cursor_from_string(s_ecs_host),
  65. .path_and_query = aws_byte_cursor_from_string(ecs_relative_uri),
  66. .tls_ctx = NULL,
  67. .auth_token = auth_token_cursor,
  68. };
  69. ecs_or_imds_provider = aws_credentials_provider_new_ecs(allocator, &ecs_options);
  70. } else if (ecs_full_uri && ecs_full_uri->len) {
  71. struct aws_uri uri;
  72. struct aws_byte_cursor uri_cstr = aws_byte_cursor_from_string(ecs_full_uri);
  73. if (AWS_OP_ERR == aws_uri_init_parse(&uri, allocator, &uri_cstr)) {
  74. goto clean_up;
  75. }
  76. struct aws_credentials_provider_ecs_options ecs_options = {
  77. .shutdown_options = *shutdown_options,
  78. .bootstrap = bootstrap,
  79. .host = uri.host_name,
  80. .path_and_query = uri.path_and_query,
  81. .tls_ctx = aws_byte_cursor_eq_c_str_ignore_case(&(uri.scheme), "HTTPS") ? tls_ctx : NULL,
  82. .auth_token = auth_token_cursor,
  83. .port = uri.port,
  84. };
  85. ecs_or_imds_provider = aws_credentials_provider_new_ecs(allocator, &ecs_options);
  86. aws_uri_clean_up(&uri);
  87. } else if (ec2_imds_disable == NULL || aws_string_eq_c_str_ignore_case(ec2_imds_disable, "false")) {
  88. struct aws_credentials_provider_imds_options imds_options = {
  89. .shutdown_options = *shutdown_options,
  90. .bootstrap = bootstrap,
  91. };
  92. ecs_or_imds_provider = aws_credentials_provider_new_imds(allocator, &imds_options);
  93. }
  94. clean_up:
  95. aws_string_destroy(ecs_relative_uri);
  96. aws_string_destroy(ecs_full_uri);
  97. aws_string_destroy(ec2_imds_disable);
  98. aws_string_destroy(ecs_token);
  99. return ecs_or_imds_provider;
  100. }
  101. struct default_chain_callback_data {
  102. struct aws_allocator *allocator;
  103. struct aws_credentials_provider *default_chain_provider;
  104. aws_on_get_credentials_callback_fn *original_callback;
  105. void *original_user_data;
  106. };
  107. static struct default_chain_callback_data *s_create_callback_data(
  108. struct aws_credentials_provider *provider,
  109. aws_on_get_credentials_callback_fn *callback,
  110. void *user_data) {
  111. struct default_chain_callback_data *callback_data =
  112. aws_mem_calloc(provider->allocator, 1, sizeof(struct default_chain_callback_data));
  113. if (callback_data == NULL) {
  114. return NULL;
  115. }
  116. callback_data->allocator = provider->allocator;
  117. callback_data->default_chain_provider = provider;
  118. callback_data->original_callback = callback;
  119. callback_data->original_user_data = user_data;
  120. aws_credentials_provider_acquire(provider);
  121. return callback_data;
  122. }
  123. static void s_destroy_callback_data(struct default_chain_callback_data *callback_data) {
  124. aws_credentials_provider_release(callback_data->default_chain_provider);
  125. aws_mem_release(callback_data->allocator, callback_data);
  126. }
  127. struct aws_credentials_provider_default_chain_impl {
  128. struct aws_atomic_var shutdowns_remaining;
  129. struct aws_credentials_provider *cached_provider;
  130. };
  131. static void s_aws_provider_default_chain_callback(
  132. struct aws_credentials *credentials,
  133. int error_code,
  134. void *user_data) {
  135. struct default_chain_callback_data *callback_data = user_data;
  136. struct aws_credentials_provider *provider = callback_data->default_chain_provider;
  137. if (credentials != NULL) {
  138. AWS_LOGF_INFO(
  139. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  140. "(id=%p) Default chain credentials provider successfully sourced credentials",
  141. (void *)provider);
  142. } else {
  143. AWS_LOGF_ERROR(
  144. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  145. "(id=%p) Default chain credentials provider failed to source credentials with error %d(%s)",
  146. (void *)provider,
  147. error_code,
  148. aws_error_debug_str(error_code));
  149. }
  150. callback_data->original_callback(credentials, error_code, callback_data->original_user_data);
  151. s_destroy_callback_data(callback_data);
  152. }
  153. static int s_credentials_provider_default_chain_get_credentials_async(
  154. struct aws_credentials_provider *provider,
  155. aws_on_get_credentials_callback_fn callback,
  156. void *user_data) {
  157. struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
  158. AWS_LOGF_DEBUG(
  159. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  160. "(id=%p) Credentials provider chain get credentials dispatch",
  161. (void *)provider);
  162. struct default_chain_callback_data *callback_data = s_create_callback_data(provider, callback, user_data);
  163. if (callback_data == NULL) {
  164. return AWS_OP_ERR;
  165. }
  166. int result = aws_credentials_provider_get_credentials(
  167. impl->cached_provider, s_aws_provider_default_chain_callback, callback_data);
  168. if (result != AWS_OP_SUCCESS) {
  169. s_destroy_callback_data(callback_data);
  170. }
  171. return result;
  172. }
  173. static void s_on_sub_provider_shutdown_completed(void *user_data) {
  174. struct aws_credentials_provider *provider = user_data;
  175. struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
  176. size_t remaining = aws_atomic_fetch_sub(&impl->shutdowns_remaining, 1);
  177. if (remaining != 1) {
  178. return;
  179. }
  180. /* Invoke our own shutdown callback */
  181. aws_credentials_provider_invoke_shutdown_callback(provider);
  182. aws_mem_release(provider->allocator, provider);
  183. }
  184. static void s_credentials_provider_default_chain_destroy(struct aws_credentials_provider *provider) {
  185. struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
  186. if (impl == NULL) {
  187. return;
  188. }
  189. aws_credentials_provider_release(impl->cached_provider);
  190. s_on_sub_provider_shutdown_completed(provider);
  191. }
  192. static struct aws_credentials_provider_vtable s_aws_credentials_provider_default_chain_vtable = {
  193. .get_credentials = s_credentials_provider_default_chain_get_credentials_async,
  194. .destroy = s_credentials_provider_default_chain_destroy,
  195. };
  196. /*
  197. * Default provider chain implementation
  198. */
  199. struct aws_credentials_provider *aws_credentials_provider_new_chain_default(
  200. struct aws_allocator *allocator,
  201. const struct aws_credentials_provider_chain_default_options *options) {
  202. struct aws_credentials_provider *provider = NULL;
  203. struct aws_credentials_provider_default_chain_impl *impl = NULL;
  204. aws_mem_acquire_many(
  205. allocator,
  206. 2,
  207. &provider,
  208. sizeof(struct aws_credentials_provider),
  209. &impl,
  210. sizeof(struct aws_credentials_provider_default_chain_impl));
  211. if (!provider) {
  212. return NULL;
  213. }
  214. AWS_ZERO_STRUCT(*provider);
  215. AWS_ZERO_STRUCT(*impl);
  216. aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_default_chain_vtable, impl);
  217. provider->shutdown_options = options->shutdown_options;
  218. /* 1 shutdown call from the provider's destroy itself */
  219. aws_atomic_init_int(&impl->shutdowns_remaining, 1);
  220. struct aws_credentials_provider_shutdown_options sub_provider_shutdown_options;
  221. AWS_ZERO_STRUCT(sub_provider_shutdown_options);
  222. sub_provider_shutdown_options.shutdown_callback = s_on_sub_provider_shutdown_completed;
  223. sub_provider_shutdown_options.shutdown_user_data = provider;
  224. struct aws_tls_ctx *tls_ctx = NULL;
  225. struct aws_credentials_provider *environment_provider = NULL;
  226. struct aws_credentials_provider *profile_provider = NULL;
  227. struct aws_credentials_provider *sts_provider = NULL;
  228. struct aws_credentials_provider *ecs_or_imds_provider = NULL;
  229. struct aws_credentials_provider *chain_provider = NULL;
  230. struct aws_credentials_provider *cached_provider = NULL;
  231. if (options->tls_ctx) {
  232. tls_ctx = aws_tls_ctx_acquire(options->tls_ctx);
  233. } else {
  234. #ifdef BYO_CRYPTO
  235. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  236. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "TLS context must be provided to credentials provider.");
  237. goto on_error;
  238. #else
  239. AWS_LOGF_INFO(
  240. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  241. "(id=%p): TLS context not provided, initializing a new one for credentials provider.",
  242. (void *)provider);
  243. struct aws_tls_ctx_options tls_options;
  244. aws_tls_ctx_options_init_default_client(&tls_options, allocator);
  245. tls_ctx = aws_tls_client_ctx_new(allocator, &tls_options);
  246. aws_tls_ctx_options_clean_up(&tls_options);
  247. if (!tls_ctx) {
  248. AWS_LOGF_ERROR(
  249. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  250. "(id=%p): failed to create a TLS context with error %s",
  251. (void *)provider,
  252. aws_error_debug_str(aws_last_error()));
  253. goto on_error;
  254. }
  255. #endif /* BYO_CRYPTO */
  256. }
  257. enum { providers_size = 4 };
  258. struct aws_credentials_provider *providers[providers_size];
  259. AWS_ZERO_ARRAY(providers);
  260. size_t index = 0;
  261. struct aws_credentials_provider_environment_options environment_options;
  262. AWS_ZERO_STRUCT(environment_options);
  263. environment_provider = aws_credentials_provider_new_environment(allocator, &environment_options);
  264. if (environment_provider == NULL) {
  265. goto on_error;
  266. }
  267. providers[index++] = environment_provider;
  268. struct aws_credentials_provider_profile_options profile_options;
  269. AWS_ZERO_STRUCT(profile_options);
  270. profile_options.bootstrap = options->bootstrap;
  271. profile_options.tls_ctx = tls_ctx;
  272. profile_options.shutdown_options = sub_provider_shutdown_options;
  273. profile_options.profile_collection_cached = options->profile_collection_cached;
  274. profile_provider = aws_credentials_provider_new_profile(allocator, &profile_options);
  275. if (profile_provider != NULL) {
  276. providers[index++] = profile_provider;
  277. /* 1 shutdown call from the profile provider's shutdown */
  278. aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
  279. }
  280. struct aws_credentials_provider_sts_web_identity_options sts_options;
  281. AWS_ZERO_STRUCT(sts_options);
  282. sts_options.bootstrap = options->bootstrap;
  283. sts_options.tls_ctx = tls_ctx;
  284. sts_options.shutdown_options = sub_provider_shutdown_options;
  285. sts_options.config_profile_collection_cached = options->profile_collection_cached;
  286. sts_provider = aws_credentials_provider_new_sts_web_identity(allocator, &sts_options);
  287. if (sts_provider != NULL) {
  288. providers[index++] = sts_provider;
  289. /* 1 shutdown call from the web identity provider's shutdown */
  290. aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
  291. }
  292. ecs_or_imds_provider = s_aws_credentials_provider_new_ecs_or_imds(
  293. allocator, &sub_provider_shutdown_options, options->bootstrap, tls_ctx);
  294. if (ecs_or_imds_provider != NULL) {
  295. providers[index++] = ecs_or_imds_provider;
  296. /* 1 shutdown call from the imds or ecs provider's shutdown */
  297. aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
  298. }
  299. AWS_FATAL_ASSERT(index <= providers_size);
  300. struct aws_credentials_provider_chain_options chain_options = {
  301. .provider_count = index,
  302. .providers = providers,
  303. };
  304. chain_provider = aws_credentials_provider_new_chain(allocator, &chain_options);
  305. if (chain_provider == NULL) {
  306. goto on_error;
  307. }
  308. /*
  309. * Transfer ownership
  310. */
  311. aws_credentials_provider_release(environment_provider);
  312. aws_credentials_provider_release(profile_provider);
  313. aws_credentials_provider_release(sts_provider);
  314. aws_credentials_provider_release(ecs_or_imds_provider);
  315. struct aws_credentials_provider_cached_options cached_options = {
  316. .source = chain_provider,
  317. .refresh_time_in_milliseconds = DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS,
  318. };
  319. cached_provider = aws_credentials_provider_new_cached(allocator, &cached_options);
  320. if (cached_provider == NULL) {
  321. goto on_error;
  322. }
  323. /*
  324. * Transfer ownership
  325. */
  326. aws_credentials_provider_release(chain_provider);
  327. impl->cached_provider = cached_provider;
  328. /* Subproviders have their own reference to the tls_ctx now */
  329. aws_tls_ctx_release(tls_ctx);
  330. return provider;
  331. on_error:
  332. /*
  333. * Have to be a bit more careful than normal with this clean up pattern since the chain/cache will
  334. * recursively destroy the other providers via ref release.
  335. *
  336. * Technically, the cached_provider can never be non-null here, but let's handle it anyways
  337. * in case someone does something weird in the future.
  338. */
  339. if (cached_provider) {
  340. aws_credentials_provider_release(cached_provider);
  341. } else if (chain_provider) {
  342. aws_credentials_provider_release(chain_provider);
  343. } else {
  344. aws_credentials_provider_release(ecs_or_imds_provider);
  345. aws_credentials_provider_release(profile_provider);
  346. aws_credentials_provider_release(sts_provider);
  347. aws_credentials_provider_release(environment_provider);
  348. }
  349. aws_tls_ctx_release(tls_ctx);
  350. aws_mem_release(allocator, provider);
  351. return NULL;
  352. }