credentials_provider_profile.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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/aws_profile.h>
  7. #include <aws/auth/private/credentials_utils.h>
  8. #include <aws/common/process.h>
  9. #include <aws/common/string.h>
  10. #include <aws/io/tls_channel_handler.h>
  11. #ifdef _MSC_VER
  12. /* allow non-constant declared initializers. */
  13. # pragma warning(disable : 4204)
  14. #endif
  15. /*
  16. * Profile provider implementation
  17. */
  18. AWS_STRING_FROM_LITERAL(s_role_arn_name, "role_arn");
  19. AWS_STRING_FROM_LITERAL(s_role_session_name_name, "role_session_name");
  20. AWS_STRING_FROM_LITERAL(s_credential_source_name, "credential_source");
  21. AWS_STRING_FROM_LITERAL(s_source_profile_name, "source_profile");
  22. static struct aws_byte_cursor s_default_session_name_pfx =
  23. AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("aws-common-runtime-profile-config");
  24. static struct aws_byte_cursor s_ec2_imds_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Ec2InstanceMetadata");
  25. static struct aws_byte_cursor s_environment_name = AWS_BYTE_CUR_INIT_FROM_STRING_LITERAL("Environment");
  26. #define MAX_SESSION_NAME_LEN ((size_t)64)
  27. struct aws_credentials_provider_profile_file_impl {
  28. struct aws_string *config_file_path;
  29. struct aws_string *credentials_file_path;
  30. struct aws_string *profile_name;
  31. struct aws_profile_collection *profile_collection_cached;
  32. };
  33. static int s_profile_file_credentials_provider_get_credentials_async(
  34. struct aws_credentials_provider *provider,
  35. aws_on_get_credentials_callback_fn callback,
  36. void *user_data) {
  37. struct aws_credentials_provider_profile_file_impl *impl = provider->impl;
  38. struct aws_credentials *credentials = NULL;
  39. struct aws_profile_collection *merged_profiles = NULL;
  40. if (impl->profile_collection_cached) {
  41. /* Use cached profile collection */
  42. merged_profiles = aws_profile_collection_acquire(impl->profile_collection_cached);
  43. } else {
  44. /*
  45. * Parse config file from file, if it exists
  46. */
  47. struct aws_profile_collection *config_profiles =
  48. aws_profile_collection_new_from_file(provider->allocator, impl->config_file_path, AWS_PST_CONFIG);
  49. if (config_profiles != NULL) {
  50. AWS_LOGF_DEBUG(
  51. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  52. "(id=%p) Profile credentials provider successfully built config profile collection from file at (%s)",
  53. (void *)provider,
  54. aws_string_c_str(impl->config_file_path));
  55. } else {
  56. AWS_LOGF_DEBUG(
  57. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  58. "(id=%p) Profile credentials provider failed to build config profile collection from file at (%s)",
  59. (void *)provider,
  60. aws_string_c_str(impl->config_file_path));
  61. }
  62. /*
  63. * Parse credentials file, if it exists
  64. */
  65. struct aws_profile_collection *credentials_profiles =
  66. aws_profile_collection_new_from_file(provider->allocator, impl->credentials_file_path, AWS_PST_CREDENTIALS);
  67. if (credentials_profiles != NULL) {
  68. AWS_LOGF_DEBUG(
  69. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  70. "(id=%p) Profile credentials provider successfully built credentials profile collection from file at "
  71. "(%s)",
  72. (void *)provider,
  73. aws_string_c_str(impl->credentials_file_path));
  74. } else {
  75. AWS_LOGF_DEBUG(
  76. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  77. "(id=%p) Profile credentials provider failed to build credentials profile collection from file at (%s)",
  78. (void *)provider,
  79. aws_string_c_str(impl->credentials_file_path));
  80. }
  81. /*
  82. * Merge the (up to) two sources into a single unified profile
  83. */
  84. merged_profiles =
  85. aws_profile_collection_new_from_merge(provider->allocator, config_profiles, credentials_profiles);
  86. aws_profile_collection_release(config_profiles);
  87. aws_profile_collection_release(credentials_profiles);
  88. }
  89. if (merged_profiles != NULL) {
  90. const struct aws_profile *profile = aws_profile_collection_get_profile(merged_profiles, impl->profile_name);
  91. if (profile != NULL) {
  92. AWS_LOGF_INFO(
  93. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  94. "(id=%p) Profile credentials provider attempting to pull credentials from profile \"%s\"",
  95. (void *)provider,
  96. aws_string_c_str(impl->profile_name));
  97. credentials = aws_credentials_new_from_profile(provider->allocator, profile);
  98. } else {
  99. AWS_LOGF_INFO(
  100. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  101. "(id=%p) Profile credentials provider could not find a profile named \"%s\"",
  102. (void *)provider,
  103. aws_string_c_str(impl->profile_name));
  104. }
  105. } else {
  106. AWS_LOGF_ERROR(
  107. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  108. "(id=%p) Profile credentials provider failed to merge config and credentials profile collections",
  109. (void *)provider);
  110. }
  111. int error_code = AWS_ERROR_SUCCESS;
  112. if (credentials == NULL) {
  113. error_code = aws_last_error();
  114. if (error_code == AWS_ERROR_SUCCESS) {
  115. error_code = AWS_AUTH_CREDENTIALS_PROVIDER_PROFILE_SOURCE_FAILURE;
  116. }
  117. }
  118. callback(credentials, error_code, user_data);
  119. /*
  120. * clean up
  121. */
  122. aws_credentials_release(credentials);
  123. aws_profile_collection_release(merged_profiles);
  124. return AWS_OP_SUCCESS;
  125. }
  126. static void s_profile_file_credentials_provider_destroy(struct aws_credentials_provider *provider) {
  127. struct aws_credentials_provider_profile_file_impl *impl = provider->impl;
  128. if (impl == NULL) {
  129. return;
  130. }
  131. aws_string_destroy(impl->config_file_path);
  132. aws_string_destroy(impl->credentials_file_path);
  133. aws_string_destroy(impl->profile_name);
  134. aws_profile_collection_release(impl->profile_collection_cached);
  135. aws_credentials_provider_invoke_shutdown_callback(provider);
  136. aws_mem_release(provider->allocator, provider);
  137. }
  138. static struct aws_credentials_provider_vtable s_aws_credentials_provider_profile_file_vtable = {
  139. .get_credentials = s_profile_file_credentials_provider_get_credentials_async,
  140. .destroy = s_profile_file_credentials_provider_destroy,
  141. };
  142. /* load a purely config/credentials file based provider. */
  143. static struct aws_credentials_provider *s_create_profile_based_provider(
  144. struct aws_allocator *allocator,
  145. struct aws_string *credentials_file_path,
  146. struct aws_string *config_file_path,
  147. const struct aws_string *profile_name,
  148. struct aws_profile_collection *profile_collection_cached) {
  149. struct aws_credentials_provider *provider = NULL;
  150. struct aws_credentials_provider_profile_file_impl *impl = NULL;
  151. aws_mem_acquire_many(
  152. allocator,
  153. 2,
  154. &provider,
  155. sizeof(struct aws_credentials_provider),
  156. &impl,
  157. sizeof(struct aws_credentials_provider_profile_file_impl));
  158. if (!provider) {
  159. return NULL;
  160. }
  161. AWS_ZERO_STRUCT(*provider);
  162. AWS_ZERO_STRUCT(*impl);
  163. aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_profile_file_vtable, impl);
  164. if (credentials_file_path) {
  165. impl->credentials_file_path = aws_string_clone_or_reuse(allocator, credentials_file_path);
  166. }
  167. if (config_file_path) {
  168. impl->config_file_path = aws_string_clone_or_reuse(allocator, config_file_path);
  169. }
  170. impl->profile_name = aws_string_clone_or_reuse(allocator, profile_name);
  171. impl->profile_collection_cached = aws_profile_collection_acquire(profile_collection_cached);
  172. return provider;
  173. }
  174. /* use the selected property that specifies a role_arn to load an STS based provider. */
  175. static struct aws_credentials_provider *s_create_sts_based_provider(
  176. struct aws_allocator *allocator,
  177. const struct aws_profile_property *role_arn_property,
  178. const struct aws_profile *profile,
  179. struct aws_string *credentials_file_path,
  180. struct aws_string *config_file_path,
  181. const struct aws_credentials_provider_profile_options *options) {
  182. struct aws_credentials_provider *provider = NULL;
  183. AWS_LOGF_INFO(
  184. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  185. "static: profile %s has role_arn property is set to %s, attempting to "
  186. "create an STS credentials provider.",
  187. aws_string_c_str(aws_profile_get_name(profile)),
  188. aws_string_c_str(aws_profile_property_get_value(role_arn_property)));
  189. const struct aws_profile_property *source_profile_property =
  190. aws_profile_get_property(profile, s_source_profile_name);
  191. const struct aws_profile_property *credential_source_property =
  192. aws_profile_get_property(profile, s_credential_source_name);
  193. const struct aws_profile_property *role_session_name = aws_profile_get_property(profile, s_role_session_name_name);
  194. char session_name_array[MAX_SESSION_NAME_LEN + 1];
  195. AWS_ZERO_ARRAY(session_name_array);
  196. if (role_session_name) {
  197. size_t to_write = aws_profile_property_get_value(role_session_name)->len;
  198. if (to_write > MAX_SESSION_NAME_LEN) {
  199. AWS_LOGF_WARN(
  200. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  201. "static: session_name property is %d bytes long, "
  202. "but the max is %d. Truncating",
  203. (int)aws_profile_property_get_value(role_session_name)->len,
  204. (int)MAX_SESSION_NAME_LEN);
  205. to_write = MAX_SESSION_NAME_LEN;
  206. }
  207. memcpy(session_name_array, aws_string_bytes(aws_profile_property_get_value(role_session_name)), to_write);
  208. } else {
  209. memcpy(session_name_array, s_default_session_name_pfx.ptr, s_default_session_name_pfx.len);
  210. snprintf(
  211. session_name_array + s_default_session_name_pfx.len,
  212. sizeof(session_name_array) - s_default_session_name_pfx.len,
  213. "-%d",
  214. aws_get_pid());
  215. }
  216. AWS_LOGF_DEBUG(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: computed session_name as %s", session_name_array);
  217. /* Automatically create a TLS context if necessary. We'd prefer that users pass one in, but can't force
  218. * them to because aws_credentials_provider_profile_options didn't always have a tls_ctx member. */
  219. struct aws_tls_ctx *tls_ctx = NULL;
  220. if (options->tls_ctx) {
  221. tls_ctx = aws_tls_ctx_acquire(options->tls_ctx);
  222. } else {
  223. #ifdef BYO_CRYPTO
  224. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "a TLS context must be provided to query STS");
  225. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  226. goto done;
  227. #else
  228. AWS_LOGF_INFO(
  229. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "TLS context not provided, initializing a new one for querying STS");
  230. struct aws_tls_ctx_options tls_options;
  231. aws_tls_ctx_options_init_default_client(&tls_options, allocator);
  232. tls_ctx = aws_tls_client_ctx_new(allocator, &tls_options);
  233. aws_tls_ctx_options_clean_up(&tls_options);
  234. if (!tls_ctx) {
  235. goto done;
  236. }
  237. #endif
  238. }
  239. struct aws_credentials_provider_sts_options sts_options = {
  240. .bootstrap = options->bootstrap,
  241. .tls_ctx = tls_ctx,
  242. .role_arn = aws_byte_cursor_from_string(aws_profile_property_get_value(role_arn_property)),
  243. .session_name = aws_byte_cursor_from_c_str(session_name_array),
  244. .duration_seconds = 0,
  245. .function_table = options->function_table,
  246. };
  247. if (source_profile_property) {
  248. AWS_LOGF_DEBUG(
  249. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  250. "static: source_profile set to %s",
  251. aws_string_c_str(aws_profile_property_get_value(source_profile_property)));
  252. sts_options.creds_provider = s_create_profile_based_provider(
  253. allocator,
  254. credentials_file_path,
  255. config_file_path,
  256. aws_profile_property_get_value(source_profile_property),
  257. options->profile_collection_cached);
  258. if (!sts_options.creds_provider) {
  259. goto done;
  260. }
  261. provider = aws_credentials_provider_new_sts(allocator, &sts_options);
  262. aws_credentials_provider_release(sts_options.creds_provider);
  263. if (!provider) {
  264. AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: failed to load STS credentials provider");
  265. }
  266. } else if (credential_source_property) {
  267. AWS_LOGF_INFO(
  268. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  269. "static: credential_source property set to %s",
  270. aws_string_c_str(aws_profile_property_get_value(credential_source_property)));
  271. if (aws_string_eq_byte_cursor_ignore_case(
  272. aws_profile_property_get_value(credential_source_property), &s_ec2_imds_name)) {
  273. struct aws_credentials_provider_imds_options imds_options = {
  274. .bootstrap = options->bootstrap,
  275. .function_table = options->function_table,
  276. };
  277. struct aws_credentials_provider *imds_provider =
  278. aws_credentials_provider_new_imds(allocator, &imds_options);
  279. if (!imds_provider) {
  280. goto done;
  281. }
  282. sts_options.creds_provider = imds_provider;
  283. provider = aws_credentials_provider_new_sts(allocator, &sts_options);
  284. aws_credentials_provider_release(imds_provider);
  285. } else if (aws_string_eq_byte_cursor_ignore_case(
  286. aws_profile_property_get_value(credential_source_property), &s_environment_name)) {
  287. struct aws_credentials_provider_environment_options env_options;
  288. AWS_ZERO_STRUCT(env_options);
  289. struct aws_credentials_provider *env_provider =
  290. aws_credentials_provider_new_environment(allocator, &env_options);
  291. if (!env_provider) {
  292. goto done;
  293. }
  294. sts_options.creds_provider = env_provider;
  295. provider = aws_credentials_provider_new_sts(allocator, &sts_options);
  296. aws_credentials_provider_release(env_provider);
  297. } else {
  298. AWS_LOGF_ERROR(
  299. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  300. "static: invalid credential_source property: %s",
  301. aws_string_c_str(aws_profile_property_get_value(credential_source_property)));
  302. aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
  303. }
  304. }
  305. done:
  306. aws_tls_ctx_release(tls_ctx);
  307. return provider;
  308. }
  309. struct aws_credentials_provider *aws_credentials_provider_new_profile(
  310. struct aws_allocator *allocator,
  311. const struct aws_credentials_provider_profile_options *options) {
  312. struct aws_credentials_provider *provider = NULL;
  313. struct aws_profile_collection *config_profiles = NULL;
  314. struct aws_profile_collection *credentials_profiles = NULL;
  315. struct aws_profile_collection *merged_profiles = NULL;
  316. struct aws_string *credentials_file_path = NULL;
  317. struct aws_string *config_file_path = NULL;
  318. struct aws_string *profile_name = NULL;
  319. profile_name = aws_get_profile_name(allocator, &options->profile_name_override);
  320. if (!profile_name) {
  321. AWS_LOGF_ERROR(
  322. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: Profile credentials parser failed to resolve profile name");
  323. goto on_finished;
  324. }
  325. if (options->profile_collection_cached) {
  326. /* Use cached profile collection */
  327. merged_profiles = aws_profile_collection_acquire(options->profile_collection_cached);
  328. } else {
  329. /* Load profile collection from files */
  330. credentials_file_path = aws_get_credentials_file_path(allocator, &options->credentials_file_name_override);
  331. if (!credentials_file_path) {
  332. AWS_LOGF_ERROR(
  333. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  334. "static: Profile credentials parser failed resolve credentials file path");
  335. goto on_finished;
  336. }
  337. config_file_path = aws_get_config_file_path(allocator, &options->config_file_name_override);
  338. if (!config_file_path) {
  339. AWS_LOGF_ERROR(
  340. AWS_LS_AUTH_CREDENTIALS_PROVIDER, "static: Profile credentials parser failed resolve config file path");
  341. goto on_finished;
  342. }
  343. config_profiles = aws_profile_collection_new_from_file(allocator, config_file_path, AWS_PST_CONFIG);
  344. credentials_profiles =
  345. aws_profile_collection_new_from_file(allocator, credentials_file_path, AWS_PST_CREDENTIALS);
  346. if (!(config_profiles || credentials_profiles)) {
  347. AWS_LOGF_ERROR(
  348. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  349. "static: Profile credentials parser could not load or parse"
  350. " a credentials or config file.");
  351. goto on_finished;
  352. }
  353. merged_profiles = aws_profile_collection_new_from_merge(allocator, config_profiles, credentials_profiles);
  354. }
  355. const struct aws_profile *profile = aws_profile_collection_get_profile(merged_profiles, profile_name);
  356. if (!profile) {
  357. AWS_LOGF_ERROR(
  358. AWS_LS_AUTH_CREDENTIALS_PROVIDER,
  359. "static: Profile credentials provider could not load"
  360. " a profile at %s.",
  361. aws_string_c_str(profile_name));
  362. goto on_finished;
  363. }
  364. const struct aws_profile_property *role_arn_property = aws_profile_get_property(profile, s_role_arn_name);
  365. if (role_arn_property) {
  366. provider = s_create_sts_based_provider(
  367. allocator, role_arn_property, profile, credentials_file_path, config_file_path, options);
  368. } else {
  369. provider = s_create_profile_based_provider(
  370. allocator, credentials_file_path, config_file_path, profile_name, options->profile_collection_cached);
  371. }
  372. on_finished:
  373. aws_profile_collection_release(config_profiles);
  374. aws_profile_collection_release(credentials_profiles);
  375. aws_profile_collection_release(merged_profiles);
  376. aws_string_destroy(credentials_file_path);
  377. aws_string_destroy(config_file_path);
  378. aws_string_destroy(profile_name);
  379. if (provider) {
  380. provider->shutdown_options = options->shutdown_options;
  381. }
  382. return provider;
  383. }