123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- /**
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- * SPDX-License-Identifier: Apache-2.0.
- */
- #include <aws/auth/credentials.h>
- #include <aws/auth/private/credentials_utils.h>
- #include <aws/common/clock.h>
- #include <aws/common/environment.h>
- #include <aws/common/logging.h>
- #include <aws/common/string.h>
- #include <aws/io/tls_channel_handler.h>
- #include <aws/io/uri.h>
- #define DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS (15 * 60 * 1000)
- #if defined(_MSC_VER)
- # pragma warning(disable : 4204)
- /*
- * For designated initialization: .providers = providers,
- * of aws_credentials_provider_chain_options in function
- * aws_credentials_provider_new_chain_default
- */
- # pragma warning(disable : 4221)
- #endif /* _MSC_VER */
- AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_relative_uri, "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI");
- AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_full_uri, "AWS_CONTAINER_CREDENTIALS_FULL_URI");
- AWS_STATIC_STRING_FROM_LITERAL(s_ecs_creds_env_token, "AWS_CONTAINER_AUTHORIZATION_TOKEN");
- AWS_STATIC_STRING_FROM_LITERAL(s_ecs_host, "169.254.170.2");
- AWS_STATIC_STRING_FROM_LITERAL(s_ec2_creds_env_disable, "AWS_EC2_METADATA_DISABLED");
- /**
- * ECS and IMDS credentials providers are mutually exclusive,
- * ECS has higher priority
- */
- static struct aws_credentials_provider *s_aws_credentials_provider_new_ecs_or_imds(
- struct aws_allocator *allocator,
- const struct aws_credentials_provider_shutdown_options *shutdown_options,
- struct aws_client_bootstrap *bootstrap,
- struct aws_tls_ctx *tls_ctx) {
- struct aws_byte_cursor auth_token_cursor;
- AWS_ZERO_STRUCT(auth_token_cursor);
- struct aws_credentials_provider *ecs_or_imds_provider = NULL;
- struct aws_string *ecs_relative_uri = NULL;
- struct aws_string *ecs_full_uri = NULL;
- struct aws_string *ec2_imds_disable = NULL;
- struct aws_string *ecs_token = NULL;
- if (aws_get_environment_value(allocator, s_ecs_creds_env_relative_uri, &ecs_relative_uri) != AWS_OP_SUCCESS ||
- aws_get_environment_value(allocator, s_ecs_creds_env_full_uri, &ecs_full_uri) != AWS_OP_SUCCESS ||
- aws_get_environment_value(allocator, s_ec2_creds_env_disable, &ec2_imds_disable) != AWS_OP_SUCCESS ||
- aws_get_environment_value(allocator, s_ecs_creds_env_token, &ecs_token) != AWS_OP_SUCCESS) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "Failed reading environment variables during default credentials provider chain initialization.");
- goto clean_up;
- }
- if (ecs_token && ecs_token->len) {
- auth_token_cursor = aws_byte_cursor_from_string(ecs_token);
- }
- /*
- * ToDo: the uri choice logic should be done in the ecs provider init logic. As it stands, it's a nightmare
- * to try and use the ecs provider anywhere outside the default chain.
- */
- if (ecs_relative_uri && ecs_relative_uri->len) {
- struct aws_credentials_provider_ecs_options ecs_options = {
- .shutdown_options = *shutdown_options,
- .bootstrap = bootstrap,
- .host = aws_byte_cursor_from_string(s_ecs_host),
- .path_and_query = aws_byte_cursor_from_string(ecs_relative_uri),
- .tls_ctx = NULL,
- .auth_token = auth_token_cursor,
- };
- ecs_or_imds_provider = aws_credentials_provider_new_ecs(allocator, &ecs_options);
- } else if (ecs_full_uri && ecs_full_uri->len) {
- struct aws_uri uri;
- struct aws_byte_cursor uri_cstr = aws_byte_cursor_from_string(ecs_full_uri);
- if (AWS_OP_ERR == aws_uri_init_parse(&uri, allocator, &uri_cstr)) {
- goto clean_up;
- }
- struct aws_credentials_provider_ecs_options ecs_options = {
- .shutdown_options = *shutdown_options,
- .bootstrap = bootstrap,
- .host = uri.host_name,
- .path_and_query = uri.path_and_query,
- .tls_ctx = aws_byte_cursor_eq_c_str_ignore_case(&(uri.scheme), "HTTPS") ? tls_ctx : NULL,
- .auth_token = auth_token_cursor,
- .port = uri.port,
- };
- ecs_or_imds_provider = aws_credentials_provider_new_ecs(allocator, &ecs_options);
- aws_uri_clean_up(&uri);
- } else if (ec2_imds_disable == NULL || aws_string_eq_c_str_ignore_case(ec2_imds_disable, "false")) {
- struct aws_credentials_provider_imds_options imds_options = {
- .shutdown_options = *shutdown_options,
- .bootstrap = bootstrap,
- };
- ecs_or_imds_provider = aws_credentials_provider_new_imds(allocator, &imds_options);
- }
- clean_up:
- aws_string_destroy(ecs_relative_uri);
- aws_string_destroy(ecs_full_uri);
- aws_string_destroy(ec2_imds_disable);
- aws_string_destroy(ecs_token);
- return ecs_or_imds_provider;
- }
- struct default_chain_callback_data {
- struct aws_allocator *allocator;
- struct aws_credentials_provider *default_chain_provider;
- aws_on_get_credentials_callback_fn *original_callback;
- void *original_user_data;
- };
- static struct default_chain_callback_data *s_create_callback_data(
- struct aws_credentials_provider *provider,
- aws_on_get_credentials_callback_fn *callback,
- void *user_data) {
- struct default_chain_callback_data *callback_data =
- aws_mem_calloc(provider->allocator, 1, sizeof(struct default_chain_callback_data));
- if (callback_data == NULL) {
- return NULL;
- }
- callback_data->allocator = provider->allocator;
- callback_data->default_chain_provider = provider;
- callback_data->original_callback = callback;
- callback_data->original_user_data = user_data;
- aws_credentials_provider_acquire(provider);
- return callback_data;
- }
- static void s_destroy_callback_data(struct default_chain_callback_data *callback_data) {
- aws_credentials_provider_release(callback_data->default_chain_provider);
- aws_mem_release(callback_data->allocator, callback_data);
- }
- struct aws_credentials_provider_default_chain_impl {
- struct aws_atomic_var shutdowns_remaining;
- struct aws_credentials_provider *cached_provider;
- };
- static void s_aws_provider_default_chain_callback(
- struct aws_credentials *credentials,
- int error_code,
- void *user_data) {
- struct default_chain_callback_data *callback_data = user_data;
- struct aws_credentials_provider *provider = callback_data->default_chain_provider;
- if (credentials != NULL) {
- AWS_LOGF_INFO(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p) Default chain credentials provider successfully sourced credentials",
- (void *)provider);
- } else {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p) Default chain credentials provider failed to source credentials with error %d(%s)",
- (void *)provider,
- error_code,
- aws_error_debug_str(error_code));
- }
- callback_data->original_callback(credentials, error_code, callback_data->original_user_data);
- s_destroy_callback_data(callback_data);
- }
- static int s_credentials_provider_default_chain_get_credentials_async(
- struct aws_credentials_provider *provider,
- aws_on_get_credentials_callback_fn callback,
- void *user_data) {
- struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
- AWS_LOGF_DEBUG(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p) Credentials provider chain get credentials dispatch",
- (void *)provider);
- struct default_chain_callback_data *callback_data = s_create_callback_data(provider, callback, user_data);
- if (callback_data == NULL) {
- return AWS_OP_ERR;
- }
- int result = aws_credentials_provider_get_credentials(
- impl->cached_provider, s_aws_provider_default_chain_callback, callback_data);
- if (result != AWS_OP_SUCCESS) {
- s_destroy_callback_data(callback_data);
- }
- return result;
- }
- static void s_on_sub_provider_shutdown_completed(void *user_data) {
- struct aws_credentials_provider *provider = user_data;
- struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
- size_t remaining = aws_atomic_fetch_sub(&impl->shutdowns_remaining, 1);
- if (remaining != 1) {
- return;
- }
- /* Invoke our own shutdown callback */
- aws_credentials_provider_invoke_shutdown_callback(provider);
- aws_mem_release(provider->allocator, provider);
- }
- static void s_credentials_provider_default_chain_destroy(struct aws_credentials_provider *provider) {
- struct aws_credentials_provider_default_chain_impl *impl = provider->impl;
- if (impl == NULL) {
- return;
- }
- aws_credentials_provider_release(impl->cached_provider);
- s_on_sub_provider_shutdown_completed(provider);
- }
- static struct aws_credentials_provider_vtable s_aws_credentials_provider_default_chain_vtable = {
- .get_credentials = s_credentials_provider_default_chain_get_credentials_async,
- .destroy = s_credentials_provider_default_chain_destroy,
- };
- /*
- * Default provider chain implementation
- */
- struct aws_credentials_provider *aws_credentials_provider_new_chain_default(
- struct aws_allocator *allocator,
- const struct aws_credentials_provider_chain_default_options *options) {
- struct aws_credentials_provider *provider = NULL;
- struct aws_credentials_provider_default_chain_impl *impl = NULL;
- aws_mem_acquire_many(
- allocator,
- 2,
- &provider,
- sizeof(struct aws_credentials_provider),
- &impl,
- sizeof(struct aws_credentials_provider_default_chain_impl));
- if (!provider) {
- return NULL;
- }
- AWS_ZERO_STRUCT(*provider);
- AWS_ZERO_STRUCT(*impl);
- aws_credentials_provider_init_base(provider, allocator, &s_aws_credentials_provider_default_chain_vtable, impl);
- provider->shutdown_options = options->shutdown_options;
- /* 1 shutdown call from the provider's destroy itself */
- aws_atomic_init_int(&impl->shutdowns_remaining, 1);
- struct aws_credentials_provider_shutdown_options sub_provider_shutdown_options;
- AWS_ZERO_STRUCT(sub_provider_shutdown_options);
- sub_provider_shutdown_options.shutdown_callback = s_on_sub_provider_shutdown_completed;
- sub_provider_shutdown_options.shutdown_user_data = provider;
- struct aws_tls_ctx *tls_ctx = NULL;
- struct aws_credentials_provider *environment_provider = NULL;
- struct aws_credentials_provider *profile_provider = NULL;
- struct aws_credentials_provider *sts_provider = NULL;
- struct aws_credentials_provider *ecs_or_imds_provider = NULL;
- struct aws_credentials_provider *chain_provider = NULL;
- struct aws_credentials_provider *cached_provider = NULL;
- if (options->tls_ctx) {
- tls_ctx = aws_tls_ctx_acquire(options->tls_ctx);
- } else {
- #ifdef BYO_CRYPTO
- aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
- AWS_LOGF_ERROR(AWS_LS_AUTH_CREDENTIALS_PROVIDER, "TLS context must be provided to credentials provider.");
- goto on_error;
- #else
- AWS_LOGF_INFO(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): TLS context not provided, initializing a new one for credentials provider.",
- (void *)provider);
- struct aws_tls_ctx_options tls_options;
- aws_tls_ctx_options_init_default_client(&tls_options, allocator);
- tls_ctx = aws_tls_client_ctx_new(allocator, &tls_options);
- aws_tls_ctx_options_clean_up(&tls_options);
- if (!tls_ctx) {
- AWS_LOGF_ERROR(
- AWS_LS_AUTH_CREDENTIALS_PROVIDER,
- "(id=%p): failed to create a TLS context with error %s",
- (void *)provider,
- aws_error_debug_str(aws_last_error()));
- goto on_error;
- }
- #endif /* BYO_CRYPTO */
- }
- enum { providers_size = 4 };
- struct aws_credentials_provider *providers[providers_size];
- AWS_ZERO_ARRAY(providers);
- size_t index = 0;
- struct aws_credentials_provider_environment_options environment_options;
- AWS_ZERO_STRUCT(environment_options);
- environment_provider = aws_credentials_provider_new_environment(allocator, &environment_options);
- if (environment_provider == NULL) {
- goto on_error;
- }
- providers[index++] = environment_provider;
- struct aws_credentials_provider_profile_options profile_options;
- AWS_ZERO_STRUCT(profile_options);
- profile_options.bootstrap = options->bootstrap;
- profile_options.tls_ctx = tls_ctx;
- profile_options.shutdown_options = sub_provider_shutdown_options;
- profile_options.profile_collection_cached = options->profile_collection_cached;
- profile_provider = aws_credentials_provider_new_profile(allocator, &profile_options);
- if (profile_provider != NULL) {
- providers[index++] = profile_provider;
- /* 1 shutdown call from the profile provider's shutdown */
- aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
- }
- struct aws_credentials_provider_sts_web_identity_options sts_options;
- AWS_ZERO_STRUCT(sts_options);
- sts_options.bootstrap = options->bootstrap;
- sts_options.tls_ctx = tls_ctx;
- sts_options.shutdown_options = sub_provider_shutdown_options;
- sts_options.config_profile_collection_cached = options->profile_collection_cached;
- sts_provider = aws_credentials_provider_new_sts_web_identity(allocator, &sts_options);
- if (sts_provider != NULL) {
- providers[index++] = sts_provider;
- /* 1 shutdown call from the web identity provider's shutdown */
- aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
- }
- ecs_or_imds_provider = s_aws_credentials_provider_new_ecs_or_imds(
- allocator, &sub_provider_shutdown_options, options->bootstrap, tls_ctx);
- if (ecs_or_imds_provider != NULL) {
- providers[index++] = ecs_or_imds_provider;
- /* 1 shutdown call from the imds or ecs provider's shutdown */
- aws_atomic_fetch_add(&impl->shutdowns_remaining, 1);
- }
- AWS_FATAL_ASSERT(index <= providers_size);
- struct aws_credentials_provider_chain_options chain_options = {
- .provider_count = index,
- .providers = providers,
- };
- chain_provider = aws_credentials_provider_new_chain(allocator, &chain_options);
- if (chain_provider == NULL) {
- goto on_error;
- }
- /*
- * Transfer ownership
- */
- aws_credentials_provider_release(environment_provider);
- aws_credentials_provider_release(profile_provider);
- aws_credentials_provider_release(sts_provider);
- aws_credentials_provider_release(ecs_or_imds_provider);
- struct aws_credentials_provider_cached_options cached_options = {
- .source = chain_provider,
- .refresh_time_in_milliseconds = DEFAULT_CREDENTIAL_PROVIDER_REFRESH_MS,
- };
- cached_provider = aws_credentials_provider_new_cached(allocator, &cached_options);
- if (cached_provider == NULL) {
- goto on_error;
- }
- /*
- * Transfer ownership
- */
- aws_credentials_provider_release(chain_provider);
- impl->cached_provider = cached_provider;
- /* Subproviders have their own reference to the tls_ctx now */
- aws_tls_ctx_release(tls_ctx);
- return provider;
- on_error:
- /*
- * Have to be a bit more careful than normal with this clean up pattern since the chain/cache will
- * recursively destroy the other providers via ref release.
- *
- * Technically, the cached_provider can never be non-null here, but let's handle it anyways
- * in case someone does something weird in the future.
- */
- if (cached_provider) {
- aws_credentials_provider_release(cached_provider);
- } else if (chain_provider) {
- aws_credentials_provider_release(chain_provider);
- } else {
- aws_credentials_provider_release(ecs_or_imds_provider);
- aws_credentials_provider_release(profile_provider);
- aws_credentials_provider_release(sts_provider);
- aws_credentials_provider_release(environment_provider);
- }
- aws_tls_ctx_release(tls_ctx);
- aws_mem_release(allocator, provider);
- return NULL;
- }
|