summaryrefslogtreecommitdiffstats
path: root/fluent-bit/src/aws/flb_aws_credentials.c
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/src/aws/flb_aws_credentials.c')
-rw-r--r--fluent-bit/src/aws/flb_aws_credentials.c862
1 files changed, 862 insertions, 0 deletions
diff --git a/fluent-bit/src/aws/flb_aws_credentials.c b/fluent-bit/src/aws/flb_aws_credentials.c
new file mode 100644
index 000000000..850142e24
--- /dev/null
+++ b/fluent-bit/src/aws/flb_aws_credentials.c
@@ -0,0 +1,862 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Fluent Bit
+ * ==========
+ * Copyright (C) 2015-2022 The Fluent Bit Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fluent-bit/flb_info.h>
+#include <fluent-bit/flb_sds.h>
+#include <fluent-bit/flb_http_client.h>
+#include <fluent-bit/flb_aws_credentials.h>
+#include <fluent-bit/flb_aws_util.h>
+#include <fluent-bit/flb_jsmn.h>
+#include <fluent-bit/flb_output_plugin.h>
+
+#include <stdlib.h>
+#include <time.h>
+
+#define FIVE_MINUTES 300
+#define TWELVE_HOURS 43200
+
+/* Credentials Environment Variables */
+#define AWS_ACCESS_KEY_ID "AWS_ACCESS_KEY_ID"
+#define AWS_SECRET_ACCESS_KEY "AWS_SECRET_ACCESS_KEY"
+#define AWS_SESSION_TOKEN "AWS_SESSION_TOKEN"
+
+#define EKS_POD_EXECUTION_ROLE "EKS_POD_EXECUTION_ROLE"
+
+/* declarations */
+static struct flb_aws_provider *standard_chain_create(struct flb_config
+ *config,
+ struct flb_tls *tls,
+ char *region,
+ char *sts_endpoint,
+ char *proxy,
+ struct
+ flb_aws_client_generator
+ *generator,
+ int eks_irsa,
+ char *profile);
+
+
+/*
+ * The standard credential provider chain:
+ * 1. Environment variables
+ * 2. Shared credentials file (AWS Profile)
+ * 3. EKS OIDC
+ * 4. EC2 IMDS
+ * 5. ECS HTTP credentials endpoint
+ *
+ * This provider will evaluate each provider in order, returning the result
+ * from the first provider that returns valid credentials.
+ *
+ * Note: Client code should use this provider by default.
+ */
+struct flb_aws_provider_chain {
+ struct mk_list sub_providers;
+
+ /*
+ * The standard chain provider picks the first successful provider and
+ * then uses it until a call to refresh is made.
+ */
+ struct flb_aws_provider *sub_provider;
+};
+
+/*
+ * Iterates through the chain and returns credentials from the first provider
+ * that successfully returns creds. Caches this provider on the implementation.
+ */
+struct flb_aws_credentials *get_from_chain(struct flb_aws_provider_chain
+ *implementation)
+{
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct flb_aws_credentials *creds = NULL;
+
+ /* find the first provider that produces a valid set of creds */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ creds = sub_provider->provider_vtable->get_credentials(sub_provider);
+ if (creds) {
+ implementation->sub_provider = sub_provider;
+ return creds;
+ }
+ }
+
+ return NULL;
+}
+
+struct flb_aws_credentials *get_credentials_fn_standard_chain(struct
+ flb_aws_provider
+ *provider)
+{
+ struct flb_aws_credentials *creds = NULL;
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = implementation->sub_provider;
+
+ if (sub_provider) {
+ return sub_provider->provider_vtable->get_credentials(sub_provider);
+ }
+
+ if (try_lock_provider(provider)) {
+ creds = get_from_chain(implementation);
+ unlock_provider(provider);
+ return creds;
+ }
+
+ /*
+ * We failed to lock the provider and sub_provider is unset. This means that
+ * another co-routine is selecting a provider from the chain.
+ */
+ flb_warn("[aws_credentials] No cached credentials are available and "
+ "a credential refresh is already in progress. The current "
+ "co-routine will retry.");
+ return NULL;
+}
+
+int init_fn_standard_chain(struct flb_aws_provider *provider)
+{
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ int ret = -1;
+
+ if (try_lock_provider(provider)) {
+ /* find the first provider that indicates successful init */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ ret = sub_provider->provider_vtable->init(sub_provider);
+ if (ret >= 0) {
+ implementation->sub_provider = sub_provider;
+ break;
+ }
+ }
+ unlock_provider(provider);
+ }
+
+ return ret;
+}
+
+/*
+ * Client code should only call refresh if there has been an
+ * error from the AWS APIs indicating creds are expired/invalid.
+ * Refresh may change the current sub_provider.
+ */
+int refresh_fn_standard_chain(struct flb_aws_provider *provider)
+{
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+ int ret = -1;
+
+ if (try_lock_provider(provider)) {
+ /* find the first provider that indicates successful refresh */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ ret = sub_provider->provider_vtable->refresh(sub_provider);
+ if (ret >= 0) {
+ implementation->sub_provider = sub_provider;
+ break;
+ }
+ }
+ unlock_provider(provider);
+ }
+
+ return ret;
+}
+
+void sync_fn_standard_chain(struct flb_aws_provider *provider)
+{
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+
+ /* set all providers to sync mode */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ sub_provider->provider_vtable->sync(sub_provider);
+ }
+}
+
+void async_fn_standard_chain(struct flb_aws_provider *provider)
+{
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+
+ /* set all providers to async mode */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ sub_provider->provider_vtable->async(sub_provider);
+ }
+}
+
+void upstream_set_fn_standard_chain(struct flb_aws_provider *provider,
+ struct flb_output_instance *ins)
+{
+ struct flb_aws_provider_chain *implementation = provider->implementation;
+ struct flb_aws_provider *sub_provider = NULL;
+ struct mk_list *tmp;
+ struct mk_list *head;
+
+ /* set all providers to async mode */
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head,
+ struct flb_aws_provider,
+ _head);
+ sub_provider->provider_vtable->upstream_set(sub_provider, ins);
+ }
+}
+
+void destroy_fn_standard_chain(struct flb_aws_provider *provider) {
+ struct flb_aws_provider *sub_provider;
+ struct flb_aws_provider_chain *implementation;
+ struct mk_list *tmp;
+ struct mk_list *head;
+
+ implementation = provider->implementation;
+
+ if (implementation) {
+ mk_list_foreach_safe(head, tmp, &implementation->sub_providers) {
+ sub_provider = mk_list_entry(head, struct flb_aws_provider,
+ _head);
+ mk_list_del(&sub_provider->_head);
+ flb_aws_provider_destroy(sub_provider);
+ }
+
+ flb_free(implementation);
+ }
+}
+
+static struct flb_aws_provider_vtable standard_chain_provider_vtable = {
+ .get_credentials = get_credentials_fn_standard_chain,
+ .init = init_fn_standard_chain,
+ .refresh = refresh_fn_standard_chain,
+ .destroy = destroy_fn_standard_chain,
+ .sync = sync_fn_standard_chain,
+ .async = async_fn_standard_chain,
+ .upstream_set = upstream_set_fn_standard_chain,
+};
+
+struct flb_aws_provider *flb_standard_chain_provider_create(struct flb_config
+ *config,
+ struct flb_tls *tls,
+ char *region,
+ char *sts_endpoint,
+ char *proxy,
+ struct
+ flb_aws_client_generator
+ *generator,
+ char *profile)
+{
+ struct flb_aws_provider *provider;
+ struct flb_aws_provider *tmp_provider;
+ char *eks_pod_role = NULL;
+ char *session_name;
+
+ eks_pod_role = getenv(EKS_POD_EXECUTION_ROLE);
+ if (eks_pod_role && strlen(eks_pod_role) > 0) {
+ /*
+ * eks fargate
+ * standard chain will be base provider used to
+ * assume the EKS_POD_EXECUTION_ROLE
+ */
+ flb_debug("[aws_credentials] Using EKS_POD_EXECUTION_ROLE=%s", eks_pod_role);
+ tmp_provider = standard_chain_create(config, tls, region, sts_endpoint,
+ proxy, generator, FLB_FALSE, profile);
+
+ if (!tmp_provider) {
+ return NULL;
+ }
+
+ session_name = flb_sts_session_name();
+ if (!session_name) {
+ flb_error("Failed to generate random STS session name");
+ flb_aws_provider_destroy(tmp_provider);
+ return NULL;
+ }
+
+ provider = flb_sts_provider_create(config, tls, tmp_provider, NULL,
+ eks_pod_role, session_name,
+ region, sts_endpoint,
+ NULL, generator);
+ if (!provider) {
+ flb_error("Failed to create EKS Fargate Credential Provider");
+ flb_aws_provider_destroy(tmp_provider);
+ return NULL;
+ }
+ /* session name can freed after provider is created */
+ flb_free(session_name);
+ session_name = NULL;
+
+ return provider;
+ }
+
+ /* standard case- not in EKS Fargate */
+ provider = standard_chain_create(config, tls, region, sts_endpoint,
+ proxy, generator, FLB_TRUE, profile);
+ return provider;
+}
+
+struct flb_aws_provider *flb_managed_chain_provider_create(struct flb_output_instance
+ *ins,
+ struct flb_config
+ *config,
+ char *config_key_prefix,
+ char *proxy,
+ struct
+ flb_aws_client_generator
+ *generator)
+{
+ flb_sds_t config_key_region;
+ flb_sds_t config_key_sts_endpoint;
+ flb_sds_t config_key_role_arn;
+ flb_sds_t config_key_external_id;
+ flb_sds_t config_key_profile;
+ const char *region = NULL;
+ const char *sts_endpoint = NULL;
+ const char *role_arn = NULL;
+ const char *external_id = NULL;
+ const char *profile = NULL;
+ char *session_name = NULL;
+ int key_prefix_len;
+ int key_max_len;
+
+ /* Provider managed dependencies */
+ struct flb_aws_provider *aws_provider = NULL;
+ struct flb_aws_provider *base_aws_provider = NULL;
+ struct flb_tls *cred_tls = NULL;
+ struct flb_tls *sts_tls = NULL;
+
+ /* Config keys */
+ key_prefix_len = strlen(config_key_prefix);
+ key_max_len = key_prefix_len + 12; /* max length of
+ "region", "sts_endpoint", "role_arn",
+ "external_id" */
+
+ /* Evaluate full config keys */
+ config_key_region = flb_sds_create_len(config_key_prefix, key_max_len);
+ strcpy(config_key_region + key_prefix_len, "region");
+ config_key_sts_endpoint = flb_sds_create_len(config_key_prefix, key_max_len);
+ strcpy(config_key_sts_endpoint + key_prefix_len, "sts_endpoint");
+ config_key_role_arn = flb_sds_create_len(config_key_prefix, key_max_len);
+ strcpy(config_key_role_arn + key_prefix_len, "role_arn");
+ config_key_external_id = flb_sds_create_len(config_key_prefix, key_max_len);
+ strcpy(config_key_external_id + key_prefix_len, "external_id");
+ config_key_profile = flb_sds_create_len(config_key_prefix, key_max_len);
+ strcpy(config_key_profile + key_prefix_len, "profile");
+
+ /* AWS provider needs a separate TLS instance */
+ cred_tls = flb_tls_create(FLB_TLS_CLIENT_MODE,
+ FLB_TRUE,
+ ins->tls_debug,
+ ins->tls_vhost,
+ ins->tls_ca_path,
+ ins->tls_ca_file,
+ ins->tls_crt_file,
+ ins->tls_key_file,
+ ins->tls_key_passwd);
+ if (!cred_tls) {
+ flb_plg_error(ins, "Failed to create TLS instance for AWS Provider");
+ flb_errno();
+ goto error;
+ }
+
+ region = flb_output_get_property(config_key_region, ins);
+ if (!region) {
+ flb_plg_error(ins, "aws_auth enabled but %s not set", config_key_region);
+ goto error;
+ }
+
+ /* Use null sts_endpoint if none provided */
+ sts_endpoint = flb_output_get_property(config_key_sts_endpoint, ins);
+ /* Get the profile from configuration */
+ profile = flb_output_get_property(config_key_profile, ins);
+ aws_provider = flb_standard_chain_provider_create(config,
+ cred_tls,
+ (char *) region,
+ (char *) sts_endpoint,
+ NULL,
+ flb_aws_client_generator(),
+ profile);
+ if (!aws_provider) {
+ flb_plg_error(ins, "Failed to create AWS Credential Provider");
+ goto error;
+ }
+
+ role_arn = flb_output_get_property(config_key_role_arn, ins);
+ if (role_arn) {
+ /* Use the STS Provider */
+ base_aws_provider = aws_provider;
+ external_id = flb_output_get_property(config_key_external_id, ins);
+
+ session_name = flb_sts_session_name();
+ if (!session_name) {
+ flb_plg_error(ins, "Failed to generate aws iam role "
+ "session name");
+ goto error;
+ }
+
+ /* STS provider needs yet another separate TLS instance */
+ sts_tls = flb_tls_create(FLB_TLS_CLIENT_MODE,
+ FLB_TRUE,
+ ins->tls_debug,
+ ins->tls_vhost,
+ ins->tls_ca_path,
+ ins->tls_ca_file,
+ ins->tls_crt_file,
+ ins->tls_key_file,
+ ins->tls_key_passwd);
+ if (!sts_tls) {
+ flb_plg_error(ins, "Failed to create TLS instance for AWS STS Credential "
+ "Provider");
+ flb_errno();
+ goto error;
+ }
+
+ aws_provider = flb_sts_provider_create(config,
+ sts_tls,
+ base_aws_provider,
+ (char *) external_id,
+ (char *) role_arn,
+ session_name,
+ (char *) region,
+ (char *) sts_endpoint,
+ NULL,
+ flb_aws_client_generator());
+ if (!aws_provider) {
+ flb_plg_error(ins, "Failed to create AWS STS Credential "
+ "Provider");
+ goto error;
+ }
+ }
+
+ /* initialize credentials in sync mode */
+ aws_provider->provider_vtable->sync(aws_provider);
+ aws_provider->provider_vtable->init(aws_provider);
+
+ /* set back to async */
+ aws_provider->provider_vtable->async(aws_provider);
+
+ /* store dependencies in aws_provider for managed cleanup */
+ aws_provider->base_aws_provider = base_aws_provider;
+ aws_provider->cred_tls = cred_tls;
+ aws_provider->sts_tls = sts_tls;
+
+ goto cleanup;
+
+error:
+ if (aws_provider) {
+ /* disconnect dependencies */
+ aws_provider->base_aws_provider = NULL;
+ aws_provider->cred_tls = NULL;
+ aws_provider->sts_tls = NULL;
+ /* destroy */
+ flb_aws_provider_destroy(aws_provider);
+ }
+ /* free dependencies */
+ if (base_aws_provider) {
+ flb_aws_provider_destroy(base_aws_provider);
+ }
+ if (cred_tls) {
+ flb_tls_destroy(cred_tls);
+ }
+ if (sts_tls) {
+ flb_tls_destroy(sts_tls);
+ }
+ aws_provider = NULL;
+
+cleanup:
+ if (config_key_region) {
+ flb_sds_destroy(config_key_region);
+ }
+ if (config_key_sts_endpoint) {
+ flb_sds_destroy(config_key_sts_endpoint);
+ }
+ if (config_key_role_arn) {
+ flb_sds_destroy(config_key_role_arn);
+ }
+ if (config_key_external_id) {
+ flb_sds_destroy(config_key_external_id);
+ }
+ if (session_name) {
+ flb_free(session_name);
+ }
+
+ return aws_provider;
+}
+
+static struct flb_aws_provider *standard_chain_create(struct flb_config
+ *config,
+ struct flb_tls *tls,
+ char *region,
+ char *sts_endpoint,
+ char *proxy,
+ struct
+ flb_aws_client_generator
+ *generator,
+ int eks_irsa,
+ char *profile)
+{
+ struct flb_aws_provider *sub_provider;
+ struct flb_aws_provider *provider;
+ struct flb_aws_provider_chain *implementation;
+
+ provider = flb_calloc(1, sizeof(struct flb_aws_provider));
+
+ if (!provider) {
+ flb_errno();
+ return NULL;
+ }
+
+ pthread_mutex_init(&provider->lock, NULL);
+
+ implementation = flb_calloc(1, sizeof(struct flb_aws_provider_chain));
+
+ if (!implementation) {
+ flb_errno();
+ flb_free(provider);
+ return NULL;
+ }
+
+ provider->provider_vtable = &standard_chain_provider_vtable;
+ provider->implementation = implementation;
+
+ /* Create chain of providers */
+ mk_list_init(&implementation->sub_providers);
+
+ sub_provider = flb_aws_env_provider_create();
+ if (!sub_provider) {
+ /* Env provider will only fail creation if a memory alloc failed */
+ flb_aws_provider_destroy(provider);
+ return NULL;
+ }
+ flb_debug("[aws_credentials] Initialized Env Provider in standard chain");
+
+ mk_list_add(&sub_provider->_head, &implementation->sub_providers);
+
+ flb_debug("[aws_credentials] creating profile %s provider", profile);
+ sub_provider = flb_profile_provider_create(profile);
+ if (sub_provider) {
+ /* Profile provider can fail if HOME env var is not set */;
+ mk_list_add(&sub_provider->_head, &implementation->sub_providers);
+ flb_debug("[aws_credentials] Initialized AWS Profile Provider in "
+ "standard chain");
+ }
+
+ if (eks_irsa == FLB_TRUE) {
+ sub_provider = flb_eks_provider_create(config, tls, region, sts_endpoint, proxy, generator);
+ if (sub_provider) {
+ /* EKS provider can fail if we are not running in k8s */;
+ mk_list_add(&sub_provider->_head, &implementation->sub_providers);
+ flb_debug("[aws_credentials] Initialized EKS Provider in standard chain");
+ }
+ }
+
+ sub_provider = flb_ecs_provider_create(config, generator);
+ if (sub_provider) {
+ /* ECS Provider will fail creation if we are not running in ECS */
+ mk_list_add(&sub_provider->_head, &implementation->sub_providers);
+ flb_debug("[aws_credentials] Initialized ECS Provider in standard chain");
+ }
+
+ sub_provider = flb_ec2_provider_create(config, generator);
+ if (!sub_provider) {
+ /* EC2 provider will only fail creation if a memory alloc failed */
+ flb_aws_provider_destroy(provider);
+ return NULL;
+ }
+ mk_list_add(&sub_provider->_head, &implementation->sub_providers);
+ flb_debug("[aws_credentials] Initialized EC2 Provider in standard chain");
+
+ return provider;
+}
+
+/* Environment Provider */
+struct flb_aws_credentials *get_credentials_fn_environment(struct
+ flb_aws_provider
+ *provider)
+{
+ char *access_key = NULL;
+ char *secret_key = NULL;
+ char *session_token = NULL;
+ struct flb_aws_credentials *creds = NULL;
+
+ flb_debug("[aws_credentials] Requesting credentials from the "
+ "env provider..");
+
+ access_key = getenv(AWS_ACCESS_KEY_ID);
+ if (!access_key || strlen(access_key) <= 0) {
+ return NULL;
+ }
+
+ secret_key = getenv(AWS_SECRET_ACCESS_KEY);
+ if (!secret_key || strlen(secret_key) <= 0) {
+ return NULL;
+ }
+
+ creds = flb_calloc(1, sizeof(struct flb_aws_credentials));
+ if (!creds) {
+ flb_errno();
+ return NULL;
+ }
+
+ creds->access_key_id = flb_sds_create(access_key);
+ if (!creds->access_key_id) {
+ flb_aws_credentials_destroy(creds);
+ flb_errno();
+ return NULL;
+ }
+
+ creds->secret_access_key = flb_sds_create(secret_key);
+ if (!creds->secret_access_key) {
+ flb_aws_credentials_destroy(creds);
+ flb_errno();
+ return NULL;
+ }
+
+ session_token = getenv(AWS_SESSION_TOKEN);
+ if (session_token && strlen(session_token) > 0) {
+ creds->session_token = flb_sds_create(session_token);
+ if (!creds->session_token) {
+ flb_aws_credentials_destroy(creds);
+ flb_errno();
+ return NULL;
+ }
+ } else {
+ creds->session_token = NULL;
+ }
+
+ return creds;
+
+}
+
+int refresh_env(struct flb_aws_provider *provider)
+{
+ char *access_key = NULL;
+ char *secret_key = NULL;
+
+ access_key = getenv(AWS_ACCESS_KEY_ID);
+ if (!access_key || strlen(access_key) <= 0) {
+ return -1;
+ }
+
+ secret_key = getenv(AWS_SECRET_ACCESS_KEY);
+ if (!secret_key || strlen(secret_key) <= 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * For the env provider, refresh simply checks if the environment
+ * variables are available.
+ */
+int refresh_fn_environment(struct flb_aws_provider *provider)
+{
+ flb_debug("[aws_credentials] Refresh called on the env provider");
+
+ return refresh_env(provider);
+}
+
+int init_fn_environment(struct flb_aws_provider *provider)
+{
+ flb_debug("[aws_credentials] Init called on the env provider");
+
+ return refresh_env(provider);
+}
+
+/*
+ * sync and async are no-ops for the env provider because it does not make
+ * network IO calls
+ */
+void sync_fn_environment(struct flb_aws_provider *provider)
+{
+ return;
+}
+
+void async_fn_environment(struct flb_aws_provider *provider)
+{
+ return;
+}
+
+void upstream_set_fn_environment(struct flb_aws_provider *provider,
+ struct flb_output_instance *ins)
+{
+ return;
+}
+
+/* Destroy is a no-op for the env provider */
+void destroy_fn_environment(struct flb_aws_provider *provider) {
+ return;
+}
+
+static struct flb_aws_provider_vtable environment_provider_vtable = {
+ .get_credentials = get_credentials_fn_environment,
+ .init = init_fn_environment,
+ .refresh = refresh_fn_environment,
+ .destroy = destroy_fn_environment,
+ .sync = sync_fn_environment,
+ .async = async_fn_environment,
+ .upstream_set = upstream_set_fn_environment,
+};
+
+struct flb_aws_provider *flb_aws_env_provider_create() {
+ struct flb_aws_provider *provider = flb_calloc(1, sizeof(
+ struct flb_aws_provider));
+
+ if (!provider) {
+ flb_errno();
+ return NULL;
+ }
+
+ provider->provider_vtable = &environment_provider_vtable;
+ provider->implementation = NULL;
+
+ return provider;
+}
+
+
+void flb_aws_credentials_destroy(struct flb_aws_credentials *creds)
+{
+ if (creds) {
+ if (creds->access_key_id) {
+ flb_sds_destroy(creds->access_key_id);
+ }
+ if (creds->secret_access_key) {
+ flb_sds_destroy(creds->secret_access_key);
+ }
+ if (creds->session_token) {
+ flb_sds_destroy(creds->session_token);
+ }
+
+ flb_free(creds);
+ }
+}
+
+void flb_aws_provider_destroy(struct flb_aws_provider *provider)
+{
+ if (provider) {
+ if (provider->implementation) {
+ provider->provider_vtable->destroy(provider);
+ }
+
+ pthread_mutex_destroy(&provider->lock);
+
+ /* free managed dependencies */
+ if (provider->base_aws_provider) {
+ flb_aws_provider_destroy(provider->base_aws_provider);
+ }
+ if (provider->cred_tls) {
+ flb_tls_destroy(provider->cred_tls);
+ }
+ if (provider->sts_tls) {
+ flb_tls_destroy(provider->sts_tls);
+ }
+
+ flb_free(provider);
+ }
+}
+
+time_t timestamp_to_epoch(const char *timestamp)
+{
+ struct tm tm = {0};
+ time_t seconds;
+ int r;
+
+ r = sscanf(timestamp, "%d-%d-%dT%d:%d:%dZ", &tm.tm_year, &tm.tm_mon,
+ &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+ if (r != 6) {
+ return -1;
+ }
+
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+ tm.tm_isdst = -1;
+ seconds = timegm(&tm);
+ if (seconds < 0) {
+ return -1;
+ }
+
+ return seconds;
+}
+
+time_t flb_aws_cred_expiration(const char *timestamp)
+{
+ time_t now;
+ time_t expiration = timestamp_to_epoch(timestamp);
+ if (expiration < 0) {
+ flb_warn("[aws_credentials] Could not parse expiration: %s", timestamp);
+ return -1;
+ }
+ /*
+ * Sanity check - expiration should be ~10 minutes to 12 hours in the future
+ * (> 12 hours is impossible with the current APIs and would likely indicate
+ * a bug in how this code processes timestamps.)
+ */
+ now = time(NULL);
+ if (expiration < (now + FIVE_MINUTES)) {
+ flb_warn("[aws_credentials] Credential expiration '%s' is less than "
+ "5 minutes in the future.",
+ timestamp);
+ }
+ if (expiration > (now + TWELVE_HOURS)) {
+ flb_warn("[aws_credentials] Credential expiration '%s' is greater than "
+ "12 hours in the future. This should not be possible.",
+ timestamp);
+ }
+ return expiration;
+}
+
+/*
+ * Fluent Bit is now multi-threaded and asynchonous with coros.
+ * The trylock prevents deadlock, and protects the provider
+ * when a cred refresh happens. The refresh frees and
+ * sets the shared cred cache, a double free could occur
+ * if two threads do it at the same exact time.
+ */
+
+/* Like a traditional try lock- it does not block if the lock is not obtained */
+int try_lock_provider(struct flb_aws_provider *provider)
+{
+ int ret = 0;
+ ret = pthread_mutex_trylock(&provider->lock);
+ if (ret != 0) {
+ return FLB_FALSE;
+ }
+ return FLB_TRUE;
+}
+
+void unlock_provider(struct flb_aws_provider *provider)
+{
+ pthread_mutex_unlock(&provider->lock);
+}