Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plugins/out_azure_blob/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ set(src
azure_blob_appendblob.c
azure_blob_blockblob.c
azure_blob_store.c
azure_blob_msiauth.c
)

FLB_PLUGIN(out_azure_blob "${src}" "")
28 changes: 27 additions & 1 deletion plugins/out_azure_blob/azure_blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,7 @@ static struct flb_config_map config_map[] = {
{
FLB_CONFIG_MAP_STR, "auth_type", "key",
0, FLB_TRUE, offsetof(struct flb_azure_blob, auth_type),
"Set the auth type: key or sas"
"Set the auth type: key, sas, managed_identity, or workload_identity"
},

{
Expand All @@ -1835,6 +1835,32 @@ static struct flb_config_map config_map[] = {
"Azure Blob SAS token"
},

{
FLB_CONFIG_MAP_STR, "client_id", NULL,
0, FLB_TRUE, offsetof(struct flb_azure_blob, client_id),
"Azure client ID for managed identity or workload identity auth. "
"For system-assigned managed identity, set to 'system'"
},

{
FLB_CONFIG_MAP_STR, "tenant_id", NULL,
0, FLB_TRUE, offsetof(struct flb_azure_blob, tenant_id),
"Azure tenant ID (required for workload identity auth)"
},

{
FLB_CONFIG_MAP_STR, "client_secret", NULL,
0, FLB_TRUE, offsetof(struct flb_azure_blob, client_secret),
"Azure client secret (optional, for service principal auth)"
},

{
FLB_CONFIG_MAP_STR, "workload_identity_token_file", NULL,
0, FLB_TRUE, offsetof(struct flb_azure_blob, workload_identity_token_file),
"Path to the workload identity token file. "
"Default: /var/run/secrets/azure/tokens/azure-identity-token"
},

{
FLB_CONFIG_MAP_STR, "database_file", NULL,
0, FLB_TRUE, offsetof(struct flb_azure_blob, database_file),
Expand Down
21 changes: 19 additions & 2 deletions plugins/out_azure_blob/azure_blob.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <fluent-bit/flb_output_plugin.h>
#include <fluent-bit/flb_upstream.h>
#include <fluent-bit/flb_oauth2.h>
#include <fluent-bit/flb_sds.h>
#include <fluent-bit/flb_sqldb.h>

Expand All @@ -48,8 +49,15 @@
#define AZURE_BLOB_APPENDBLOB 0
#define AZURE_BLOB_BLOCKBLOB 1

#define AZURE_BLOB_AUTH_KEY 0
#define AZURE_BLOB_AUTH_SAS 1
#define AZURE_BLOB_AUTH_KEY 0
#define AZURE_BLOB_AUTH_SAS 1
#define AZURE_BLOB_AUTH_MI_SYSTEM 2
#define AZURE_BLOB_AUTH_MI_USER 3
#define AZURE_BLOB_AUTH_WI 4

/* MSAL authorization URL template */
#define FLB_AZURE_BLOB_MSAL_AUTH_URL_TEMPLATE \
"https://login.microsoftonline.com/%s/oauth2/v2.0/token"

struct flb_azure_blob {
int auto_create_container;
Expand All @@ -65,6 +73,10 @@ struct flb_azure_blob {
flb_sds_t date_key;
flb_sds_t auth_type;
flb_sds_t sas_token;
flb_sds_t client_id;
flb_sds_t tenant_id;
flb_sds_t client_secret;
flb_sds_t workload_identity_token_file;
flb_sds_t database_file;
size_t part_size;
time_t upload_parts_timeout;
Expand Down Expand Up @@ -121,6 +133,11 @@ struct flb_azure_blob {
unsigned char *decoded_sk; /* decoded shared key */
size_t decoded_sk_size; /* size of decoded shared key */

/* OAuth2 (managed identity / workload identity) */
flb_sds_t oauth_url;
struct flb_oauth2 *o;
pthread_mutex_t token_mutex;

#ifdef FLB_HAVE_SQLDB
/*
* SQLite by default is not built with multi-threading enabled, and
Expand Down
97 changes: 96 additions & 1 deletion plugins/out_azure_blob/azure_blob_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "azure_blob.h"
#include "azure_blob_conf.h"
#include "azure_blob_db.h"
#include "azure_blob_msiauth.h"

#include <sys/types.h>
#include <sys/stat.h>
Expand Down Expand Up @@ -599,6 +600,29 @@ struct flb_azure_blob *flb_azure_blob_conf_create(struct flb_output_instance *in
else if (strcasecmp(tmp, "sas") == 0) {
ctx->atype = AZURE_BLOB_AUTH_SAS;
}
else if (strcasecmp(tmp, "managed_identity") == 0) {
if (!ctx->client_id) {
flb_plg_error(ctx->ins,
"managed_identity auth requires 'client_id' "
"(set to 'system' for system-assigned)");
Comment thread
temporaer marked this conversation as resolved.
return NULL;
}
if (strcasecmp(ctx->client_id, "system") == 0) {
ctx->atype = AZURE_BLOB_AUTH_MI_SYSTEM;
}
else {
ctx->atype = AZURE_BLOB_AUTH_MI_USER;
}
}
else if (strcasecmp(tmp, "workload_identity") == 0) {
ctx->atype = AZURE_BLOB_AUTH_WI;
if (!ctx->tenant_id || !ctx->client_id) {
flb_plg_error(ctx->ins,
"workload_identity auth requires "
"'tenant_id' and 'client_id'");
return NULL;
}
}
else {
flb_plg_error(ctx->ins, "invalid auth_type value '%s'", tmp);
return NULL;
Expand Down Expand Up @@ -755,6 +779,59 @@ struct flb_azure_blob *flb_azure_blob_conf_create(struct flb_output_instance *in
flb_sds_printf(&ctx->shared_key_prefix, "SharedKey %s:", ctx->account_name);
}

/* Create OAuth2 context for managed identity / workload identity */
if (ctx->atype == AZURE_BLOB_AUTH_MI_SYSTEM ||
ctx->atype == AZURE_BLOB_AUTH_MI_USER) {
/* Construct IMDS URL */
if (ctx->atype == AZURE_BLOB_AUTH_MI_SYSTEM) {
ctx->oauth_url = flb_sds_create_size(
sizeof(FLB_AZURE_BLOB_MSIAUTH_URL_TEMPLATE) + 1);
if (!ctx->oauth_url) {
return NULL;
}
flb_sds_snprintf(&ctx->oauth_url, flb_sds_alloc(ctx->oauth_url),
FLB_AZURE_BLOB_MSIAUTH_URL_TEMPLATE, "", "");
}
else {
ctx->oauth_url = flb_sds_create_size(
sizeof(FLB_AZURE_BLOB_MSIAUTH_URL_TEMPLATE) +
sizeof("&client_id=") + flb_sds_len(ctx->client_id));
if (!ctx->oauth_url) {
return NULL;
}
flb_sds_snprintf(&ctx->oauth_url, flb_sds_alloc(ctx->oauth_url),
FLB_AZURE_BLOB_MSIAUTH_URL_TEMPLATE,
"&client_id=", ctx->client_id);
}

ctx->o = flb_oauth2_create(config, ctx->oauth_url, 3000);
if (!ctx->o) {
flb_plg_error(ctx->ins, "cannot create OAuth2 context for IMDS");
return NULL;
}
flb_stream_disable_async_mode(&ctx->o->u->base);
pthread_mutex_init(&ctx->token_mutex, NULL);
}
else if (ctx->atype == AZURE_BLOB_AUTH_WI) {
/* Construct Azure AD token endpoint URL */
ctx->oauth_url = flb_sds_create_size(
sizeof(FLB_AZURE_BLOB_MSAL_AUTH_URL_TEMPLATE) +
flb_sds_len(ctx->tenant_id));
if (!ctx->oauth_url) {
return NULL;
}
flb_sds_snprintf(&ctx->oauth_url, flb_sds_alloc(ctx->oauth_url),
FLB_AZURE_BLOB_MSAL_AUTH_URL_TEMPLATE, ctx->tenant_id);

ctx->o = flb_oauth2_create(config, ctx->oauth_url, 3000);
if (!ctx->o) {
flb_plg_error(ctx->ins, "cannot create OAuth2 context for workload identity");
return NULL;
}
flb_stream_disable_async_mode(&ctx->o->u->base);
pthread_mutex_init(&ctx->token_mutex, NULL);
}

/* Sanitize path: remove any ending slash */
if (ctx->path) {
if (ctx->path[flb_sds_len(ctx->path) - 1] == '/') {
Expand All @@ -778,7 +855,11 @@ struct flb_azure_blob *flb_azure_blob_conf_create(struct flb_output_instance *in
ctx->btype == AZURE_BLOB_APPENDBLOB ? "appendblob" : "blockblob",
ctx->emulator_mode ? "yes" : "no",
ctx->real_endpoint ? ctx->real_endpoint : "no",
ctx->atype == AZURE_BLOB_AUTH_KEY ? "key" : "sas");
ctx->atype == AZURE_BLOB_AUTH_KEY ? "key" :
ctx->atype == AZURE_BLOB_AUTH_SAS ? "sas" :
ctx->atype == AZURE_BLOB_AUTH_MI_SYSTEM ? "managed_identity (system)" :
ctx->atype == AZURE_BLOB_AUTH_MI_USER ? "managed_identity (user)" :
"workload_identity");
return ctx;
}

Expand Down Expand Up @@ -822,6 +903,20 @@ void flb_azure_blob_conf_destroy(struct flb_azure_blob *ctx)
flb_sds_destroy(ctx->shared_key_prefix);
}

if (ctx->oauth_url) {
flb_sds_destroy(ctx->oauth_url);
}

if (ctx->o) {
flb_oauth2_destroy(ctx->o);
}

if (ctx->atype == AZURE_BLOB_AUTH_MI_SYSTEM ||
ctx->atype == AZURE_BLOB_AUTH_MI_USER ||
ctx->atype == AZURE_BLOB_AUTH_WI) {
pthread_mutex_destroy(&ctx->token_mutex);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if (ctx->u) {
flb_upstream_destroy(ctx->u);
}
Expand Down
51 changes: 51 additions & 0 deletions plugins/out_azure_blob/azure_blob_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
#include <fluent-bit/flb_base64.h>
#include <fluent-bit/flb_crypto.h>
#include <fluent-bit/flb_hmac.h>
#include <fluent-bit/flb_oauth2.h>
#include <fluent-bit/flb_sds.h>
#include <fluent-bit/flb_kv.h>

#include "azure_blob.h"
#include "azure_blob_uri.h"
#include "azure_blob_msiauth.h"

static int hmac_sha256_sign(unsigned char out[32],
unsigned char *key, size_t key_len,
Expand Down Expand Up @@ -294,10 +296,12 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
ssize_t content_length, int blob_type,
int content_type, int content_encoding)
{
int ret;
int len;
time_t now;
struct tm tm;
char tmp[64];
char *token;
flb_sds_t can_req;
flb_sds_t auth;

Expand Down Expand Up @@ -358,6 +362,53 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
flb_sds_destroy(can_req);
flb_sds_destroy(auth);
}
else if (ctx->atype == AZURE_BLOB_AUTH_MI_SYSTEM ||
ctx->atype == AZURE_BLOB_AUTH_MI_USER) {
pthread_mutex_lock(&ctx->token_mutex);

if (flb_oauth2_token_expired(ctx->o) == FLB_TRUE) {
token = flb_azure_blob_msiauth_token_get(ctx->o);
if (!token) {
flb_plg_error(ctx->ins, "error retrieving managed identity token");
pthread_mutex_unlock(&ctx->token_mutex);
return -1;
}
}

auth = flb_sds_create_size(flb_sds_len(ctx->o->access_token) + 8);
flb_sds_cat_safe(&auth, "Bearer ", 7);
flb_sds_cat_safe(&auth, ctx->o->access_token,
flb_sds_len(ctx->o->access_token));
flb_http_add_header(c, "Authorization", 13, auth, flb_sds_len(auth));
flb_sds_destroy(auth);

pthread_mutex_unlock(&ctx->token_mutex);
}
else if (ctx->atype == AZURE_BLOB_AUTH_WI) {
pthread_mutex_lock(&ctx->token_mutex);

if (flb_oauth2_token_expired(ctx->o) == FLB_TRUE) {
ret = flb_azure_blob_workload_identity_token_get(
ctx->o,
ctx->workload_identity_token_file,
ctx->client_id,
ctx->tenant_id);
if (ret == -1) {
flb_plg_error(ctx->ins, "error retrieving workload identity token");
pthread_mutex_unlock(&ctx->token_mutex);
return -1;
}
}

auth = flb_sds_create_size(flb_sds_len(ctx->o->access_token) + 8);
flb_sds_cat_safe(&auth, "Bearer ", 7);
flb_sds_cat_safe(&auth, ctx->o->access_token,
flb_sds_len(ctx->o->access_token));
flb_http_add_header(c, "Authorization", 13, auth, flb_sds_len(auth));
flb_sds_destroy(auth);

pthread_mutex_unlock(&ctx->token_mutex);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/* Set callback context to the HTTP client context */
flb_http_set_callback_context(c, ctx->ins->callback);
Expand Down
Loading