|  | 
| 23 | 23 | #include <fluent-bit/flb_jsmn.h> | 
| 24 | 24 | #include <fluent-bit/flb_record_accessor.h> | 
| 25 | 25 | #include <fluent-bit/flb_ra_key.h> | 
|  | 26 | +#include <fluent-bit/flb_utils.h> | 
| 26 | 27 | 
 | 
| 27 | 28 | #include "kube_conf.h" | 
| 28 | 29 | #include "kube_meta.h" | 
| @@ -282,19 +283,106 @@ int fetch_pod_service_map(struct flb_kube *ctx, char *api_server_url, | 
| 282 | 283 |     return 0; | 
| 283 | 284 | } | 
| 284 | 285 | 
 | 
| 285 |  | -/* Determine platform by checking aws-auth configmap */ | 
|  | 286 | +/* Determine platform by checking serviceaccount token issuer */ | 
| 286 | 287 | int determine_platform(struct flb_kube *ctx) | 
| 287 | 288 | { | 
| 288 | 289 |     int ret; | 
| 289 |  | -    char *config_buf; | 
| 290 |  | -    size_t config_size; | 
| 291 |  | - | 
| 292 |  | -    ret = get_api_server_configmap(ctx, KUBE_SYSTEM_NAMESPACE, AWS_AUTH_CONFIG_MAP, &config_buf, &config_size); | 
| 293 |  | -    if (ret != -1) { | 
| 294 |  | -        flb_free(config_buf); | 
| 295 |  | -        return 1; | 
|  | 290 | +    char *token_buf = NULL; | 
|  | 291 | +    size_t token_size; | 
|  | 292 | +    char *payload = NULL; | 
|  | 293 | +    size_t payload_len; | 
|  | 294 | +    char *issuer_start, *issuer_end; | 
|  | 295 | +     | 
|  | 296 | +    /* Read serviceaccount token */ | 
|  | 297 | +    ret = flb_utils_read_file(FLB_KUBE_TOKEN, &token_buf, &token_size); | 
|  | 298 | +    if (ret != 0 || !token_buf) { | 
|  | 299 | +        return -1; | 
|  | 300 | +    } | 
|  | 301 | +     | 
|  | 302 | +    /* JWT tokens have 3 parts separated by dots: header.payload.signature */ | 
|  | 303 | +    char *first_dot = strchr(token_buf, '.'); | 
|  | 304 | +    if (!first_dot) { | 
|  | 305 | +        flb_free(token_buf); | 
|  | 306 | +        return -1; | 
|  | 307 | +    } | 
|  | 308 | +     | 
|  | 309 | +    char *second_dot = strchr(first_dot + 1, '.'); | 
|  | 310 | +    if (!second_dot) { | 
|  | 311 | +        flb_free(token_buf); | 
|  | 312 | +        return -1; | 
|  | 313 | +    } | 
|  | 314 | +     | 
|  | 315 | +    /* Extract and decode the payload (middle part) */ | 
|  | 316 | +    size_t payload_b64_len = second_dot - (first_dot + 1); | 
|  | 317 | +    char *payload_b64 = flb_malloc(payload_b64_len + 1); | 
|  | 318 | +    if (!payload_b64) { | 
|  | 319 | +        flb_free(token_buf); | 
|  | 320 | +        return -1; | 
|  | 321 | +    } | 
|  | 322 | +     | 
|  | 323 | +    memcpy(payload_b64, first_dot + 1, payload_b64_len); | 
|  | 324 | +    payload_b64[payload_b64_len] = '\0'; | 
|  | 325 | +     | 
|  | 326 | +    /* Base64 decode the payload */ | 
|  | 327 | +    payload = flb_malloc(payload_b64_len * 3 / 4 + 4); /* Conservative size estimate */ | 
|  | 328 | +    if (!payload) { | 
|  | 329 | +        flb_free(token_buf); | 
|  | 330 | +        flb_free(payload_b64); | 
|  | 331 | +        return -1; | 
|  | 332 | +    } | 
|  | 333 | +     | 
|  | 334 | +    ret = flb_base64_decode((unsigned char *)payload, payload_b64_len * 3 / 4 + 4,  | 
|  | 335 | +                           &payload_len, (unsigned char *)payload_b64, payload_b64_len); | 
|  | 336 | +     | 
|  | 337 | +    flb_free(token_buf); | 
|  | 338 | +    flb_free(payload_b64); | 
|  | 339 | +     | 
|  | 340 | +    if (ret != 0) { | 
|  | 341 | +        flb_free(payload); | 
|  | 342 | +        return -1; | 
|  | 343 | +    } | 
|  | 344 | +     | 
|  | 345 | +    payload[payload_len] = '\0'; | 
|  | 346 | +     | 
|  | 347 | +    /* Look for "iss" field in the JSON payload */ | 
|  | 348 | +    issuer_start = strstr(payload, "\"iss\":"); | 
|  | 349 | +    if (!issuer_start) { | 
|  | 350 | +        flb_free(payload); | 
|  | 351 | +        return -1; | 
|  | 352 | +    } | 
|  | 353 | +     | 
|  | 354 | +    /* Skip to the value part */ | 
|  | 355 | +    issuer_start = strchr(issuer_start, ':'); | 
|  | 356 | +    if (!issuer_start) { | 
|  | 357 | +        flb_free(payload); | 
|  | 358 | +        return -1; | 
| 296 | 359 |     } | 
| 297 |  | -    return -1; | 
|  | 360 | +    issuer_start++; | 
|  | 361 | +     | 
|  | 362 | +    /* Skip whitespace and opening quote */ | 
|  | 363 | +    while (*issuer_start == ' ' || *issuer_start == '\t') issuer_start++; | 
|  | 364 | +    if (*issuer_start != '"') { | 
|  | 365 | +        flb_free(payload); | 
|  | 366 | +        return -1; | 
|  | 367 | +    } | 
|  | 368 | +    issuer_start++; | 
|  | 369 | +     | 
|  | 370 | +    /* Find closing quote */ | 
|  | 371 | +    issuer_end = strchr(issuer_start, '"'); | 
|  | 372 | +    if (!issuer_end) { | 
|  | 373 | +        flb_free(payload); | 
|  | 374 | +        return -1; | 
|  | 375 | +    } | 
|  | 376 | +     | 
|  | 377 | +    /* Check if issuer contains EKS OIDC URL pattern */ | 
|  | 378 | +    /* EKS OIDC URLs follow pattern: https://oidc.eks.{region}.amazonaws.com/id/{cluster-id} */ | 
|  | 379 | +    if (strstr(issuer_start, "oidc.eks.") && strstr(issuer_start, ".amazonaws.com/id/")) { | 
|  | 380 | +        flb_free(payload); | 
|  | 381 | +        return 1; /* EKS detected */ | 
|  | 382 | +    } | 
|  | 383 | +     | 
|  | 384 | +    flb_free(payload); | 
|  | 385 | +    return -1; /* Not EKS */ | 
| 298 | 386 | } | 
| 299 | 387 | 
 | 
| 300 | 388 | /* Gather pods list information from Kubelet */ | 
|  | 
0 commit comments