Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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_logs_ingestion/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(src
azure_logs_ingestion.c
azure_logs_ingestion_conf.c
azure_logs_ingestion_msiauth.c
)

FLB_PLUGIN(out_azure_logs_ingestion "${src}" "")
86 changes: 54 additions & 32 deletions plugins/out_azure_logs_ingestion/azure_logs_ingestion.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#include "azure_logs_ingestion.h"
#include "azure_logs_ingestion_conf.h"
#include "azure_logs_ingestion_msiauth.h"

static int cb_azure_logs_ingestion_init(struct flb_output_instance *ins,
struct flb_config *config, void *data)
Expand Down Expand Up @@ -170,48 +171,63 @@ flb_sds_t get_az_li_token(struct flb_az_li *ctx)
flb_plg_error(ctx->ins, "error locking mutex");
return NULL;
}

/* Retrieve access token only if expired */
if (flb_oauth2_token_expired(ctx->u_auth) == FLB_TRUE) {
flb_plg_debug(ctx->ins, "token expired. getting new token");
/* Clear any previous oauth2 payload content */
flb_oauth2_payload_clear(ctx->u_auth);

ret = flb_oauth2_payload_append(ctx->u_auth, "grant_type", 10,
"client_credentials", 18);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;

if (ctx->auth_type == FLB_AZ_LI_AUTH_MANAGED_IDENTITY_SYSTEM ||
ctx->auth_type == FLB_AZ_LI_AUTH_MANAGED_IDENTITY_USER) {
/* Use MSI authentication */
token = flb_azure_li_msiauth_token_get(ctx->u_auth);
if (!token) {
flb_plg_error(ctx->ins, "error retrieving MSI access token");
goto token_cleanup;
}
flb_plg_debug(ctx->ins, "got azure MSI token");
}
else {
/* Use service principal authentication */
/* Clear any previous oauth2 payload content */
flb_oauth2_payload_clear(ctx->u_auth);

ret = flb_oauth2_payload_append(ctx->u_auth, "grant_type", 10,
"client_credentials", 18);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}

ret = flb_oauth2_payload_append(ctx->u_auth, "scope", 5, FLB_AZ_LI_AUTH_SCOPE,
sizeof(FLB_AZ_LI_AUTH_SCOPE) - 1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}
ret = flb_oauth2_payload_append(ctx->u_auth, "scope", 5, FLB_AZ_LI_AUTH_SCOPE,
sizeof(FLB_AZ_LI_AUTH_SCOPE) - 1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}

ret = flb_oauth2_payload_append(ctx->u_auth, "client_id", 9,
ctx->client_id, -1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}
ret = flb_oauth2_payload_append(ctx->u_auth, "client_id", 9,
ctx->client_id, -1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}

ret = flb_oauth2_payload_append(ctx->u_auth, "client_secret", 13,
ctx->client_secret, -1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}
ret = flb_oauth2_payload_append(ctx->u_auth, "client_secret", 13,
ctx->client_secret, -1);
if (ret == -1) {
flb_plg_error(ctx->ins, "error appending oauth2 params");
goto token_cleanup;
}

token = flb_oauth2_token_get(ctx->u_auth);
token = flb_oauth2_token_get(ctx->u_auth);

/* Copy string to prevent race conditions */
if (!token) {
flb_plg_error(ctx->ins, "error retrieving oauth2 access token");
goto token_cleanup;
/* Copy string to prevent race conditions */
if (!token) {
flb_plg_error(ctx->ins, "error retrieving oauth2 access token");
goto token_cleanup;
}
flb_plg_debug(ctx->ins, "got azure token");
}
flb_plg_debug(ctx->ins, "got azure token");
}

/* Reached this code-block means, got new token or token not expired */
Expand Down Expand Up @@ -393,6 +409,12 @@ static struct flb_config_map config_map[] = {
0, FLB_TRUE, offsetof(struct flb_az_li, client_secret),
"Set the client secret of the AAD application"
},
{
FLB_CONFIG_MAP_STR, "auth_type", "service_principal",
0, FLB_TRUE, offsetof(struct flb_az_li, auth_type_str),
"Set the authentication type: 'service_principal' or 'managed_identity'. "
"For managed_identity, use 'system' as client_id for system-assigned identity, or specify the managed identity's client ID"
},
{
FLB_CONFIG_MAP_STR, "dce_url", (char *)NULL,
0, FLB_TRUE, offsetof(struct flb_az_li, dce_url),
Expand Down
11 changes: 11 additions & 0 deletions plugins/out_azure_logs_ingestion/azure_logs_ingestion.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
/* refresh token every 60 minutes */
#define FLB_AZ_LI_TOKEN_TIMEOUT 3600

/* Authentication types */
typedef enum {
FLB_AZ_LI_AUTH_SERVICE_PRINCIPAL = 0, /* Client ID + Client Secret */
FLB_AZ_LI_AUTH_MANAGED_IDENTITY_SYSTEM, /* System-assigned managed identity */
FLB_AZ_LI_AUTH_MANAGED_IDENTITY_USER /* User-assigned managed identity */
} flb_az_li_auth_type;

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_output.h>
#include <fluent-bit/flb_sds.h>
Expand All @@ -48,6 +55,10 @@ struct flb_az_li {
flb_sds_t dcr_id;
flb_sds_t table_name;

/* Authentication */
int auth_type;
char *auth_type_str;

/* time_generated: on/off */
int time_generated;
/* time key name */
Expand Down
122 changes: 93 additions & 29 deletions plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "azure_logs_ingestion.h"
#include "azure_logs_ingestion_conf.h"
#include "azure_logs_ingestion_msiauth.h"

struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,
struct flb_config *config)
Expand All @@ -41,11 +42,9 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,
return NULL;
}

/* Set the conext in output_instance so that we can retrieve it later */
/* Set the context in output_instance so that we can retrieve it later */
ctx->ins = ins;
ctx->config = config;
/* Set context */
flb_output_set_context(ins, ctx);

/* Load config map */
ret = flb_output_config_map_set(ins, (void *) ctx);
Expand All @@ -54,21 +53,45 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,
return NULL;
}

/* config: 'client_id' */
if (!ctx->client_id) {
flb_plg_error(ins, "property 'client_id' is not defined");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
/* config: 'tenant_id' */
if (!ctx->tenant_id) {
flb_plg_error(ins, "property 'tenant_id' is not defined");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
/* config: 'client_secret' */
if (!ctx->client_secret) {
flb_plg_error(ins, "property 'client_secret' is not defined");
/* Auth method validation and setup */
if (!ctx->auth_type_str || strlen(ctx->auth_type_str) == 0) {
/* Default to service_principal if auth_type_str is NULL or empty */
ctx->auth_type = FLB_AZ_LI_AUTH_SERVICE_PRINCIPAL;

/* Verify required parameters for Service Principal auth */
if (!ctx->tenant_id || !ctx->client_id || !ctx->client_secret) {
flb_plg_error(ins, "When using service_principal auth, tenant_id, client_id, and client_secret are required");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
}
else if (strcasecmp(ctx->auth_type_str, "service_principal") == 0) {
ctx->auth_type = FLB_AZ_LI_AUTH_SERVICE_PRINCIPAL;

/* Verify required parameters for Service Principal auth */
if (!ctx->tenant_id || !ctx->client_id || !ctx->client_secret) {
flb_plg_error(ins, "When using service_principal auth, tenant_id, client_id, and client_secret are required");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
}
else if (strcasecmp(ctx->auth_type_str, "managed_identity") == 0) {
/* Check if client_id indicates system-assigned or user-assigned managed identity */
if (!ctx->client_id) {
flb_plg_error(ins, "When using managed_identity auth, client_id must be set to 'system' for system-assigned or the managed identity client ID");
flb_az_li_ctx_destroy(ctx);
return NULL;
}

if (strcasecmp(ctx->client_id, "system") == 0) {
ctx->auth_type = FLB_AZ_LI_AUTH_MANAGED_IDENTITY_SYSTEM;
} else {
ctx->auth_type = FLB_AZ_LI_AUTH_MANAGED_IDENTITY_USER;
}
}
else {
flb_plg_error(ins, "Invalid auth_type '%s'. Valid options are: 'service_principal' or 'managed_identity'",
ctx->auth_type_str);
flb_az_li_ctx_destroy(ctx);
return NULL;
}
Expand All @@ -91,16 +114,55 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,
return NULL;
}

/* Allocate and set auth url */
ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_AUTH_URL_TMPLT) - 1 +
flb_sds_len(ctx->tenant_id));
if (!ctx->auth_url) {
flb_errno();
flb_az_li_ctx_destroy(ctx);
return NULL;
/* Allocate and set auth url based on authentication method */
if (ctx->auth_type == FLB_AZ_LI_AUTH_MANAGED_IDENTITY_SYSTEM) {
/* System-assigned managed identity */
ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_MSIAUTH_URL_TEMPLATE) - 1);
if (!ctx->auth_url) {
flb_errno();
flb_az_li_ctx_destroy(ctx);
return NULL;
}
if (flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url),
FLB_AZ_LI_MSIAUTH_URL_TEMPLATE, "", "") < 0) {
flb_plg_error(ins, "failed to build auth URL for system-assigned managed identity");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
}
else if (ctx->auth_type == FLB_AZ_LI_AUTH_MANAGED_IDENTITY_USER) {
/* User-assigned managed identity */
ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_MSIAUTH_URL_TEMPLATE) - 1 +
sizeof("&client_id=") - 1 +
flb_sds_len(ctx->client_id));
if (!ctx->auth_url) {
flb_errno();
flb_az_li_ctx_destroy(ctx);
return NULL;
}
if (flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url),
FLB_AZ_LI_MSIAUTH_URL_TEMPLATE, "&client_id=", ctx->client_id) < 0) {
flb_plg_error(ins, "failed to build auth URL for user-assigned managed identity");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
}
else {
/* Service principal authentication */
ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_AUTH_URL_TMPLT) - 1 +
flb_sds_len(ctx->tenant_id));
if (!ctx->auth_url) {
flb_errno();
flb_az_li_ctx_destroy(ctx);
return NULL;
}
if (flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url),
FLB_AZ_LI_AUTH_URL_TMPLT, ctx->tenant_id) < 0) {
flb_plg_error(ins, "failed to build auth URL for service principal");
flb_az_li_ctx_destroy(ctx);
return NULL;
}
}
flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url),
FLB_AZ_LI_AUTH_URL_TMPLT, ctx->tenant_id);

/* Allocate and set dce full url */
ctx->dce_u_url = flb_sds_create_size(sizeof(FLB_AZ_LI_DCE_URL_TMPLT) - 1 +
Expand Down Expand Up @@ -130,8 +192,7 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,

/* Create upstream context for Log Ingsetion endpoint */
ctx->u_dce = flb_upstream_create_url(config, ctx->dce_url,
FLB_AZ_LI_TLS_MODE, ins->tls);
if (!ctx->u_dce) {
FLB_AZ_LI_TLS_MODE, ins->tls); if (!ctx->u_dce) {
flb_plg_error(ins, "upstream creation failed");
flb_az_li_ctx_destroy(ctx);
return NULL;
Expand All @@ -141,6 +202,9 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins,
flb_plg_info(ins, "dce_url='%s', dcr='%s', table='%s', stream='Custom-%s'",
ctx->dce_url, ctx->dcr_id, ctx->table_name, ctx->table_name);

/* Set context only after all validation and initialization is complete */
flb_output_set_context(ins, ctx);

return ctx;
}

Expand Down
Loading