Skip to content

Commit 10ec400

Browse files
author
thimmegowni.venkatesu
committed
azure_kusto: Added support for region-based(Global and China cloud) authentication for Azure Kusto
1 parent 1dcc0b7 commit 10ec400

File tree

6 files changed

+147
-13
lines changed

6 files changed

+147
-13
lines changed

plugins/out_azure_kusto/azure_kusto.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ static int azure_kusto_get_service_principal_token(struct flb_azure_kusto *ctx)
8282
return -1;
8383
}
8484

85-
ret = flb_oauth2_payload_append(ctx->o, "scope", 5, FLB_AZURE_KUSTO_SCOPE, 39);
85+
/* scope depends on cloud environment */
86+
const char *scope = flb_azure_kusto_get_scope(ctx->cloud_environment);
87+
ret = flb_oauth2_payload_append(ctx->o, "scope", 5, scope, strlen(scope));
88+
8689
if (ret == -1) {
8790
flb_plg_error(ctx->ins, "error appending oauth2 params");
8891
return -1;

plugins/out_azure_kusto/azure_kusto.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,21 @@ typedef enum {
4343
FLB_AZURE_KUSTO_AUTH_WORKLOAD_IDENTITY /* Workload Identity */
4444
} flb_azure_kusto_auth_type;
4545

46-
/* Kusto streaming inserts oauth scope */
47-
#define FLB_AZURE_KUSTO_SCOPE "https://help.kusto.windows.net/.default"
46+
/* Cloud environment */
47+
typedef enum {
48+
FLB_AZURE_CLOUD_GLOBAL = 0,
49+
FLB_AZURE_CLOUD_CHINA
50+
} flb_azure_cloud_environment;
51+
52+
/* Kusto streaming inserts oauth scope (per cloud) */
53+
#define FLB_AZURE_KUSTO_SCOPE_GLOBAL "https://help.kusto.windows.net/.default"
54+
#define FLB_AZURE_KUSTO_SCOPE_CHINA "https://help.kusto.chinacloudapi.cn/.default"
4855

49-
/* MSAL authorization URL */
50-
#define FLB_MSAL_AUTH_URL_TEMPLATE \
56+
/* MSAL authorization URL (per cloud) */
57+
#define FLB_MSAL_AUTH_URL_TEMPLATE_GLOBAL \
5158
"https://login.microsoftonline.com/%s/oauth2/v2.0/token"
59+
#define FLB_MSAL_AUTH_URL_TEMPLATE_CHINA \
60+
"https://login.chinacloudapi.cn/%s/oauth2/v2.0/token"
5261

5362
#define FLB_AZURE_KUSTO_MGMT_URI_PATH "/v1/rest/mgmt"
5463
#define FLB_AZURE_KUSTO_MGMT_BODY_TEMPLATE "{\"csl\":\"%s\", \"db\": \"NetDefaultDB\"}"
@@ -74,8 +83,8 @@ typedef enum {
7483

7584
#define FLB_AZURE_IMDS_ENDPOINT "/metadata/identity/oauth2/token"
7685
#define FLB_AZURE_IMDS_API_VERSION "2018-02-01"
77-
#define FLB_AZURE_IMDS_RESOURCE "https://api.kusto.windows.net/"
78-
86+
#define FLB_AZURE_IMDS_RESOURCE_GLOBAL "https://api.kusto.windows.net/"
87+
#define FLB_AZURE_IMDS_RESOURCE_CHINA "https://api.kusto.chinacloudapi.cn/"
7988

8089
struct flb_azure_kusto_resources {
8190
struct flb_upstream_ha *blob_ha;
@@ -105,6 +114,9 @@ struct flb_azure_kusto {
105114
char *auth_type_str;
106115
char *workload_identity_token_file;
107116

117+
/* Cloud environment selection (default: Global) */
118+
int cloud_environment;
119+
108120
/* compress payload */
109121
int compression_enabled;
110122

@@ -176,6 +188,18 @@ struct flb_azure_kusto {
176188
struct flb_output_instance *ins;
177189
};
178190

191+
/* Helper to get per-cloud scope string */
192+
static inline const char *flb_azure_kusto_get_scope(int cloud_env)
193+
{
194+
return cloud_env == FLB_AZURE_CLOUD_CHINA ? FLB_AZURE_KUSTO_SCOPE_CHINA : FLB_AZURE_KUSTO_SCOPE_GLOBAL;
195+
}
196+
197+
/* Helper to get IMDS resource per cloud */
198+
static inline const char *flb_azure_kusto_get_imds_resource(int cloud_env)
199+
{
200+
return cloud_env == FLB_AZURE_CLOUD_CHINA ? FLB_AZURE_IMDS_RESOURCE_CHINA : FLB_AZURE_IMDS_RESOURCE_GLOBAL;
201+
}
202+
179203
flb_sds_t get_azure_kusto_token(struct flb_azure_kusto *ctx);
180204
flb_sds_t execute_ingest_csl_command(struct flb_azure_kusto *ctx, const char *csl);
181205

plugins/out_azure_kusto/azure_kusto_conf.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,25 @@
3232
#include "azure_kusto_conf.h"
3333
#include "azure_msiauth.h"
3434

35+
/* Cloud helpers: resolve MSAL auth URL template and Kusto scope/IMDS resource */
36+
static const char *get_msal_auth_url_template(int cloud_env)
37+
{
38+
if (cloud_env == FLB_AZURE_CLOUD_CHINA) {
39+
return FLB_MSAL_AUTH_URL_TEMPLATE_CHINA;
40+
}
41+
return FLB_MSAL_AUTH_URL_TEMPLATE_GLOBAL;
42+
}
43+
44+
static const char *get_kusto_scope(int cloud_env)
45+
{
46+
return flb_azure_kusto_get_scope(cloud_env);
47+
}
48+
49+
static const char *get_imds_resource(int cloud_env)
50+
{
51+
return flb_azure_kusto_get_imds_resource(cloud_env);
52+
}
53+
3554
/* Constants for PCG random number generator */
3655
#define PCG_DEFAULT_MULTIPLIER_64 6364136223846793005ULL
3756
#define PCG_DEFAULT_INCREMENT_64 1442695040888963407ULL
@@ -782,6 +801,12 @@ struct flb_azure_kusto *flb_azure_kusto_conf_create(struct flb_output_instance *
782801
return NULL;
783802
}
784803

804+
/* Determine cloud environment dynamically from ingestion_endpoint */
805+
ctx->cloud_environment = FLB_AZURE_CLOUD_GLOBAL; /* default */
806+
if (ctx->ingestion_endpoint && strstr(ctx->ingestion_endpoint, "chinacloudapi.cn") != NULL) {
807+
ctx->cloud_environment = FLB_AZURE_CLOUD_CHINA;
808+
}
809+
785810
/* config: 'database_name' */
786811
if (ctx->database_name == NULL) {
787812
flb_plg_error(ctx->ins, "property 'database_name' is not defined");
@@ -825,15 +850,15 @@ struct flb_azure_kusto *flb_azure_kusto_conf_create(struct flb_output_instance *
825850
}
826851
} else {
827852
/* Standard OAuth2 for service principal or workload identity */
828-
ctx->oauth_url = flb_sds_create_size(sizeof(FLB_MSAL_AUTH_URL_TEMPLATE) - 1 +
829-
flb_sds_len(ctx->tenant_id));
853+
const char *tmpl = get_msal_auth_url_template(ctx->cloud_environment);
854+
ctx->oauth_url = flb_sds_create_size(strlen(tmpl) - 1 + flb_sds_len(ctx->tenant_id));
830855
if (!ctx->oauth_url) {
831856
flb_errno();
832857
flb_azure_kusto_conf_destroy(ctx);
833858
return NULL;
834859
}
835860
flb_sds_snprintf(&ctx->oauth_url, flb_sds_alloc(ctx->oauth_url),
836-
FLB_MSAL_AUTH_URL_TEMPLATE, ctx->tenant_id);
861+
tmpl, ctx->tenant_id);
837862
}
838863

839864
ctx->resources = flb_calloc(1, sizeof(struct flb_azure_kusto_resources));

plugins/out_azure_kusto/azure_msiauth.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <fluent-bit/flb_http_client.h>
2727

2828
#include "azure_msiauth.h"
29+
#include "azure_kusto.h"
2930

3031
char *flb_azure_msiauth_token_get(struct flb_oauth2 *ctx)
3132
{
@@ -176,7 +177,16 @@ int flb_azure_workload_identity_token_get(struct flb_oauth2 *ctx, const char *to
176177
body = flb_sds_cat(body, "&client_assertion=", 18);
177178
body = flb_sds_cat(body, federated_token, flb_sds_len(federated_token));
178179
/* Use the correct scope and length for Kusto */
179-
body = flb_sds_cat(body, "&scope=https://help.kusto.windows.net/.default", 46);
180+
{
181+
int cloud_env = FLB_AZURE_CLOUD_GLOBAL;
182+
if ((ctx->host && strstr(ctx->host, "chinacloudapi.cn") != NULL) ||
183+
(ctx->uri && strstr(ctx->uri, "chinacloudapi.cn") != NULL)) {
184+
cloud_env = FLB_AZURE_CLOUD_CHINA;
185+
}
186+
const char *scope = flb_azure_kusto_get_scope(cloud_env);
187+
body = flb_sds_cat(body, "&scope=", -1);
188+
body = flb_sds_cat(body, scope, strlen(scope));
189+
}
180190

181191
if (!body) {
182192
/* This check might be redundant if flb_sds_cat handles errors, but safe */

plugins/out_azure_kusto/azure_msiauth.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
/* MSAL authorization URL */
2323
#define FLB_AZURE_MSIAUTH_URL_TEMPLATE \
24-
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01%s%s&resource=https://api.kusto.windows.net"
24+
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2021-02-01%s%s&resource=%s"
2525

2626
char *flb_azure_msiauth_token_get(struct flb_oauth2 *ctx);
2727
int flb_azure_workload_identity_token_get(struct flb_oauth2 *ctx, const char *token_file, const char *client_id, const char *tenant_id);

tests/runtime/out_azure_kusto.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ void flb_test_azure_kusto_managed_identity_system(void);
3030
void flb_test_azure_kusto_managed_identity_user(void);
3131
void flb_test_azure_kusto_service_principal(void);
3232
void flb_test_azure_kusto_workload_identity(void);
33+
void flb_test_azure_kusto_cloud_global_inference(void);
34+
void flb_test_azure_kusto_cloud_china_inference(void);
3335

3436
/* Test list */
3537
TEST_LIST = {
@@ -38,6 +40,8 @@ TEST_LIST = {
3840
{"managed_identity_user", flb_test_azure_kusto_managed_identity_user},
3941
{"service_principal", flb_test_azure_kusto_service_principal},
4042
{"workload_identity", flb_test_azure_kusto_workload_identity},
43+
{"cloud_global_inference", flb_test_azure_kusto_cloud_global_inference},
44+
{"cloud_china_inference", flb_test_azure_kusto_cloud_china_inference},
4145
{NULL, NULL}
4246
};
4347

@@ -210,4 +214,72 @@ void flb_test_azure_kusto_workload_identity(void)
210214

211215
flb_stop(ctx);
212216
flb_destroy(ctx);
213-
}
217+
}
218+
219+
/* Test for cloud inference: "Global", based on ingestion_endpoint */
220+
void flb_test_azure_kusto_cloud_global_inference(void)
221+
{
222+
int ret;
223+
flb_ctx_t *ctx;
224+
int in_ffd;
225+
int out_ffd;
226+
227+
ctx = flb_create();
228+
flb_service_set(ctx, "Flush", "1", "Grace", "1", "Log_Level", "error", NULL);
229+
230+
in_ffd = flb_input(ctx, (char *) "lib", NULL);
231+
TEST_CHECK(in_ffd >= 0);
232+
flb_input_set(ctx, in_ffd, "tag", "test", NULL);
233+
234+
out_ffd = flb_output(ctx, (char *) "azure_kusto", NULL);
235+
TEST_CHECK(out_ffd >= 0);
236+
flb_output_set(ctx, out_ffd, "match", "test", NULL);
237+
flb_output_set(ctx, out_ffd, "auth_type", "service_principal", NULL);
238+
flb_output_set(ctx, out_ffd, "tenant_id", "your-tenant-id", NULL);
239+
flb_output_set(ctx, out_ffd, "client_id", "your-client-id", NULL);
240+
flb_output_set(ctx, out_ffd, "client_secret", "your-client-secret", NULL);
241+
/* Global ingestion endpoint */
242+
flb_output_set(ctx, out_ffd, "ingestion_endpoint", "https://ingest-CLUSTER.kusto.windows.net", NULL);
243+
flb_output_set(ctx, out_ffd, "database_name", "telemetrydb", NULL);
244+
flb_output_set(ctx, out_ffd, "table_name", "logs", NULL);
245+
246+
ret = flb_start(ctx);
247+
TEST_CHECK(ret == 0);
248+
249+
flb_stop(ctx);
250+
flb_destroy(ctx);
251+
}
252+
253+
/* Test for cloud inference: "China", based on ingestion_endpoint */
254+
void flb_test_azure_kusto_cloud_china_inference(void)
255+
{
256+
int ret;
257+
flb_ctx_t *ctx;
258+
int in_ffd;
259+
int out_ffd;
260+
261+
ctx = flb_create();
262+
flb_service_set(ctx, "Flush", "1", "Grace", "1", "Log_Level", "error", NULL);
263+
264+
in_ffd = flb_input(ctx, (char *) "lib", NULL);
265+
TEST_CHECK(in_ffd >= 0);
266+
flb_input_set(ctx, in_ffd, "tag", "test", NULL);
267+
268+
out_ffd = flb_output(ctx, (char *) "azure_kusto", NULL);
269+
TEST_CHECK(out_ffd >= 0);
270+
flb_output_set(ctx, out_ffd, "match", "test", NULL);
271+
flb_output_set(ctx, out_ffd, "auth_type", "service_principal", NULL);
272+
flb_output_set(ctx, out_ffd, "tenant_id", "your-tenant-id", NULL);
273+
flb_output_set(ctx, out_ffd, "client_id", "your-client-id", NULL);
274+
flb_output_set(ctx, out_ffd, "client_secret", "your-client-secret", NULL);
275+
/* China ingestion endpoint */
276+
flb_output_set(ctx, out_ffd, "ingestion_endpoint", "https://ingest-CLUSTER.kusto.chinacloudapi.cn", NULL);
277+
flb_output_set(ctx, out_ffd, "database_name", "telemetrydb", NULL);
278+
flb_output_set(ctx, out_ffd, "table_name", "logs", NULL);
279+
280+
ret = flb_start(ctx);
281+
TEST_CHECK(ret == 0);
282+
283+
flb_stop(ctx);
284+
flb_destroy(ctx);
285+
}

0 commit comments

Comments
 (0)