From 51fe57d48f4b3ccd2b662434d7541424fc37fc3a Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 15:28:31 +0900 Subject: [PATCH 1/8] fips: Add FIPS initializing component Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_fips.h | 25 +++++++++ src/CMakeLists.txt | 1 + src/flb_fips.c | 100 ++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 include/fluent-bit/flb_fips.h create mode 100644 src/flb_fips.c diff --git a/include/fluent-bit/flb_fips.h b/include/fluent-bit/flb_fips.h new file mode 100644 index 00000000000..4c14ab40ca4 --- /dev/null +++ b/include/fluent-bit/flb_fips.h @@ -0,0 +1,25 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2026 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. + */ + +#ifndef FLB_FIPS_H +#define FLB_FIPS_H + +struct flb_config; + +int flb_fips_init(struct flb_config *config); + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a47a5d9d658..fa7875155f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -38,6 +38,7 @@ set(src flb_output.c flb_output_thread.c flb_config.c + flb_fips.c flb_config_map.c flb_socket.c flb_network.c diff --git a/src/flb_fips.c b/src/flb_fips.c new file mode 100644 index 00000000000..584a853f134 --- /dev/null +++ b/src/flb_fips.c @@ -0,0 +1,100 @@ +/* Fluent Bit + * ========== + * Copyright (C) 2015-2026 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 +#include +#include + +#ifdef FLB_HAVE_OPENSSL +#include +#include +#include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#include +#endif +#endif + +static void log_openssl_error(void) +{ +#ifdef FLB_HAVE_OPENSSL + char errbuf[256]; + unsigned long err; + + err = ERR_get_error(); + if (err != 0) { + ERR_error_string_n(err, errbuf, sizeof(errbuf)); + flb_error("[fips] OpenSSL error: %s", errbuf); + } +#endif +} + +int flb_fips_init(struct flb_config *config) +{ + int ret; + + if (config == NULL) { + return -1; + } + + if (config->fips_mode != FLB_TRUE) { + return 0; + } + + if (config->fips_mode_active == FLB_TRUE) { + return 0; + } + +#ifndef FLB_HAVE_OPENSSL + flb_error("[fips] security.fips_mode requires Fluent Bit to be built with OpenSSL"); + return -1; +#else +#if OPENSSL_VERSION_NUMBER < 0x30000000L + flb_error("[fips] security.fips_mode requires OpenSSL 3.0 or later"); + return -1; +#else + if (OSSL_PROVIDER_load(NULL, "base") == NULL) { + flb_error("[fips] failed to load OpenSSL base provider"); + log_openssl_error(); + return -1; + } + + if (OSSL_PROVIDER_load(NULL, "fips") == NULL) { + flb_error("[fips] failed to load OpenSSL FIPS provider"); + log_openssl_error(); + return -1; + } + + ret = EVP_default_properties_enable_fips(NULL, 1); + if (ret != 1) { + flb_error("[fips] failed to enable OpenSSL FIPS default properties"); + log_openssl_error(); + return -1; + } + + ret = EVP_default_properties_is_fips_enabled(NULL); + if (ret != 1) { + flb_error("[fips] OpenSSL FIPS default properties are not enabled"); + return -1; + } + + config->fips_mode_active = FLB_TRUE; + flb_info("[fips] OpenSSL FIPS mode enabled"); + + return 0; +#endif +#endif +} From d7e9997bb1d031d5a8856d269ea3030d6343c811 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 15:29:32 +0900 Subject: [PATCH 2/8] config: Add a system config for FIPS Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_config.h | 4 ++++ src/flb_config.c | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/include/fluent-bit/flb_config.h b/include/fluent-bit/flb_config.h index 3ebcb5edbae..5e3a5f747f6 100644 --- a/include/fluent-bit/flb_config.h +++ b/include/fluent-bit/flb_config.h @@ -291,6 +291,9 @@ struct flb_config { int enable_chunk_trace; #endif /* FLB_HAVE_CHUNK_TRACE */ + int fips_mode; + int fips_mode_active; + int enable_hot_reload; int ensure_thread_safety_on_hot_reloading; unsigned int hot_reloaded_count; @@ -378,6 +381,7 @@ enum conf_type { #define FLB_CONF_STR_STREAMS_FILE "Streams_File" #define FLB_CONF_STR_STREAMS_STR_CONV "sp.convert_from_str_to_num" #define FLB_CONF_STR_CONV_NAN "json.convert_nan_to_null" +#define FLB_CONF_STR_FIPS_MODE "security.fips_mode" /* FLB_HAVE_HTTP_SERVER */ #ifdef FLB_HAVE_HTTP_SERVER diff --git a/src/flb_config.c b/src/flb_config.c index f6993114fcd..7a8bf797347 100644 --- a/src/flb_config.c +++ b/src/flb_config.c @@ -63,6 +63,10 @@ struct flb_service_config service_configs[] = { FLB_CONF_TYPE_BOOL, offsetof(struct flb_config, convert_nan_to_null)}, + {FLB_CONF_STR_FIPS_MODE, + FLB_CONF_TYPE_BOOL, + offsetof(struct flb_config, fips_mode)}, + {FLB_CONF_STR_DAEMON, FLB_CONF_TYPE_BOOL, offsetof(struct flb_config, daemon)}, @@ -285,6 +289,10 @@ struct flb_config *flb_config_init() /* json */ config->convert_nan_to_null = FLB_FALSE; + /* FIPS */ + config->fips_mode = FLB_FALSE; + config->fips_mode_active = FLB_FALSE; + #ifdef FLB_HAVE_HTTP_SERVER config->http_ctx = NULL; config->http_server = FLB_FALSE; From ca0ef669af51669534d1cdbb08d07ae267adda8c Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 15:30:04 +0900 Subject: [PATCH 3/8] engine: Add a verification step for FIPS on enabled Signed-off-by: Hiroshi Hatake --- src/flb_engine.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/flb_engine.c b/src/flb_engine.c index 63178da843c..d986f521dec 100644 --- a/src/flb_engine.c +++ b/src/flb_engine.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -919,6 +920,11 @@ int flb_engine_start(struct flb_config *config) return -1; } + ret = flb_fips_init(config); + if (ret != 0) { + return -1; + } + if (engine_has_fluentbit_logs_input(config)) { flb_log_pipeline_enable(config); } From 61951b351346227b4791c7f4ab5cb1dec0279880 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 15:30:38 +0900 Subject: [PATCH 4/8] bin: Provide a command line argument for FIPS verification Signed-off-by: Hiroshi Hatake --- src/fluent-bit.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/fluent-bit.c b/src/fluent-bit.c index 14e5f5682a4..b74d68313f9 100644 --- a/src/fluent-bit.c +++ b/src/fluent-bit.c @@ -60,6 +60,7 @@ #include #include #include +#include #ifdef FLB_HAVE_MTRACE #include @@ -92,6 +93,7 @@ struct flb_stacktrace flb_st; #endif #define FLB_LONG_SUPERVISOR (1024 + 5) +#define FLB_LONG_ENABLE_FIPS (1024 + 6) #define FLB_HELP_TEXT 0 #define FLB_HELP_JSON 1 @@ -173,6 +175,7 @@ static void flb_help(int rc, struct flb_config *config) print_opt("-q, --quiet", "quiet mode"); print_opt("-S, --sosreport", "support report for Enterprise customers"); print_opt("-Y, --enable-hot-reload", "enable for hot reloading"); + print_opt(" --enable-fips", "require OpenSSL FIPS mode at startup"); print_opt("-W, --disable-thread-safety-on-hot-reloading", "disable thread safety on hot reloading"); print_opt("-V, --version", "show version number"); print_opt("-h, --help", "print this help"); @@ -1079,6 +1082,7 @@ static int flb_main_run(int argc, char **argv) { "http_port", required_argument, NULL, 'P' }, #endif { "enable-hot-reload", no_argument, NULL, 'Y' }, + { "enable-fips", no_argument, NULL, FLB_LONG_ENABLE_FIPS }, #ifdef FLB_SYSTEM_WINDOWS { "windows_maxstdio", required_argument, NULL, 'M' }, #endif @@ -1300,6 +1304,10 @@ static int flb_main_run(int argc, char **argv) case 'Y': flb_cf_section_property_add(cf_opts, service->properties, FLB_CONF_STR_HOT_RELOAD, 0, "on", 0); break; + case FLB_LONG_ENABLE_FIPS: + flb_cf_section_property_add(cf_opts, service->properties, + FLB_CONF_STR_FIPS_MODE, 0, "on", 0); + break; case 'W': flb_cf_section_property_add(cf_opts, service->properties, FLB_CONF_STR_HOT_RELOAD_ENSURE_THREAD_SAFETY, 0, "off", 0); @@ -1412,6 +1420,12 @@ static int flb_main_run(int argc, char **argv) flb_utils_error(FLB_ERR_CFG_FLUSH); } + if (flb_fips_init(config) != 0) { + flb_cf_destroy(cf_opts); + flb_destroy(ctx); + return -1; + } + /* debug or trace */ if (config->verbose >= FLB_LOG_DEBUG) { flb_utils_print_setup(config); From 18be86430ae907630d2b5c284876709fa974b308 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 15:31:16 +0900 Subject: [PATCH 5/8] out_s3: Add safe guard for FIPS compliance Signed-off-by: Hiroshi Hatake --- plugins/out_s3/s3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/out_s3/s3.c b/plugins/out_s3/s3.c index ac70da12957..1651a57fe2a 100644 --- a/plugins/out_s3/s3.c +++ b/plugins/out_s3/s3.c @@ -638,7 +638,6 @@ static int cb_s3_init(struct flb_output_instance *ins, const char *tmp; struct flb_s3 *ctx = NULL; struct flb_aws_client_generator *generator; - (void) config; (void) data; char *ep; struct flb_split_entry *tok; @@ -685,6 +684,13 @@ static int cb_s3_init(struct flb_output_instance *ins, return -1; } + if (config->fips_mode == FLB_TRUE && ctx->send_content_md5 == FLB_TRUE) { + flb_plg_error(ctx->ins, + "send_content_md5 uses MD5 and is not available " + "when security.fips_mode is enabled"); + return -1; + } + action = s3_get_retry_exhausted_action(ctx->retry_exhausted_action_str); if (action == -1) { flb_plg_error(ctx->ins, From 3047d5c1a1d7d963960ef21d626226153b221b32 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 16:54:13 +0900 Subject: [PATCH 6/8] out_azure_blob: Block MD5 hash on fips enabled Signed-off-by: Hiroshi Hatake --- plugins/out_azure_blob/azure_blob.c | 10 +++ plugins/out_azure_blob/azure_blob_blockblob.c | 85 ++++++++++++++----- 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/plugins/out_azure_blob/azure_blob.c b/plugins/out_azure_blob/azure_blob.c index 57ffd90ad43..4b230339579 100644 --- a/plugins/out_azure_blob/azure_blob.c +++ b/plugins/out_azure_blob/azure_blob.c @@ -1127,6 +1127,16 @@ static int send_blob(struct flb_config *config, } else if (event_type == FLB_EVENT_TYPE_BLOBS) { block_id = azb_block_blob_id_blob(ctx, name, part_id); + if (!block_id) { + flb_plg_error(ctx->ins, "could not generate block id"); + flb_free(generated_random_string); + generated_random_string = NULL; + flb_sds_destroy(ref_name); + if (tmp_path_prefix) { + flb_sds_destroy(tmp_path_prefix); + } + return FLB_RETRY; + } uri = azb_block_blob_uri(ctx, path_prefix, name, block_id, 0, generated_random_string); ref_name = flb_sds_printf(&ref_name, "file=%s:%" PRIu64, name, part_id); diff --git a/plugins/out_azure_blob/azure_blob_blockblob.c b/plugins/out_azure_blob/azure_blob_blockblob.c index 356c0ad24d6..3bb04a3f530 100644 --- a/plugins/out_azure_blob/azure_blob_blockblob.c +++ b/plugins/out_azure_blob/azure_blob_blockblob.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "azure_blob.h" @@ -220,18 +221,21 @@ char *azb_block_blob_id_logs(uint64_t *ms) /* * Generate a block id for blob type events: * - * Azure Blob requires that Blobs IDs do not exceed 64 bytes, so we generate a MD5 - * of the path and append the part number to it, we add some zeros for padding since - * all blocks id MUST have the same length. + * Azure Blob requires block IDs to have the same length and the base64-encoded + * value must not exceed 64 bytes. The non-FIPS path keeps the original + * MD5-derived format for compatibility. When FIPS mode is enabled, use the + * first 128 bits of SHA-256 rendered as hex plus the same fixed-width suffix. */ -char *azb_block_blob_id_blob(struct flb_azure_blob *ctx, char *path, int64_t part_id) +char *azb_block_blob_id_blob(struct flb_azure_blob *ctx, char *path, uint64_t part_id) { int i; int len; int ret; + int fips_mode; unsigned char md5[16] = {0}; + unsigned char sha256[32] = {0}; char tmp[128]; - flb_sds_t md5_hex; + flb_sds_t digest_hex; size_t size; size_t o_len; char *b64; @@ -240,27 +244,57 @@ char *azb_block_blob_id_blob(struct flb_azure_blob *ctx, char *path, int64_t par * block ids in base64 cannot exceed 64 bytes, so we hash the path to avoid * exceeding the lenght and then just append the part number. */ - ret = flb_hash_simple(FLB_HASH_MD5, (unsigned char *) path, strlen(path), - md5, sizeof(md5)); - if (ret != 0) { - flb_plg_error(ctx->ins, "cannot hash block id for path %s", path); - return NULL; + fips_mode = FLB_FALSE; + if (ctx->config != NULL && ctx->config->fips_mode == FLB_TRUE) { + fips_mode = FLB_TRUE; } - /* convert md5 to hex string (32 byte hex string) */ - md5_hex = flb_sds_create_size(32); - if (!md5_hex) { - return NULL; - } + if (fips_mode == FLB_TRUE) { + ret = flb_hash_simple(FLB_HASH_SHA256, (unsigned char *) path, strlen(path), + sha256, sizeof(sha256)); + if (ret != 0) { + flb_plg_error(ctx->ins, "cannot hash block id for path %s", path); + return NULL; + } + + digest_hex = flb_sds_create_size(32); + if (!digest_hex) { + return NULL; + } + + for (i = 0; i < 16; i++) { + snprintf(digest_hex + (i * 2), 3, "%02x", sha256[i]); + } + flb_sds_len_set(digest_hex, 32); - for (i = 0; i < 16; i++) { - snprintf(md5_hex + (i * 2), 3, "%02x", md5[i]); + len = snprintf(tmp, sizeof(tmp) - 1, "%s.flb-part.%06" PRIu64, + digest_hex, part_id); + flb_sds_destroy(digest_hex); } - flb_sds_len_set(md5_hex, 32); + else { + ret = flb_hash_simple(FLB_HASH_MD5, (unsigned char *) path, strlen(path), + md5, sizeof(md5)); + if (ret != 0) { + flb_plg_error(ctx->ins, "cannot hash block id for path %s", path); + return NULL; + } + + /* convert md5 to hex string (32 byte hex string) */ + digest_hex = flb_sds_create_size(32); + if (!digest_hex) { + return NULL; + } - /* append part number */ - len = snprintf(tmp, sizeof(tmp) - 1, "%s.flb-part.%06ld", md5_hex, part_id); - flb_sds_destroy(md5_hex); + for (i = 0; i < 16; i++) { + snprintf(digest_hex + (i * 2), 3, "%02x", md5[i]); + } + flb_sds_len_set(digest_hex, 32); + + /* append part number */ + len = snprintf(tmp, sizeof(tmp) - 1, "%s.flb-part.%06" PRIu64, + digest_hex, part_id); + flb_sds_destroy(digest_hex); + } size = 64 + 1; b64 = flb_calloc(1, size); @@ -441,6 +475,15 @@ int azb_block_blob_commit_file_parts(struct flb_azure_blob *ctx, uint64_t file_i id = atol(sentry->value); block_id = azb_block_blob_id_blob(ctx, path, id); + if (block_id == NULL) { + flb_plg_error(ctx->ins, + "could not generate block id for file id=%" PRIu64 + " name %s part=%" PRIu64, + file_id, path, id); + flb_sds_destroy(payload); + flb_utils_split_free(list); + return -1; + } cfl_sds_cat_safe(&payload, " ", 2); cfl_sds_cat_safe(&payload, "", 13); From dca071f0cbeb086cfdea77181246cd5d98f8929e Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 16:54:50 +0900 Subject: [PATCH 7/8] tests: runtime: Add a test case for sha256 hash with FIPS Signed-off-by: Hiroshi Hatake --- tests/internal/azure_blob_path.c | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/internal/azure_blob_path.c b/tests/internal/azure_blob_path.c index d89117ad29b..7d668292e48 100644 --- a/tests/internal/azure_blob_path.c +++ b/tests/internal/azure_blob_path.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "../../plugins/out_azure_blob/azure_blob.h" #include "../../plugins/out_azure_blob/azure_blob_uri.h" @@ -478,6 +479,41 @@ void test_block_blob_commit_requires_suffix(void) ctx_cleanup(&ctx); } +void test_block_blob_id_uses_sha256_in_fips_mode(void) +{ + struct flb_config config; + struct flb_azure_blob ctx; + char *default_id; + char *fips_id; + + memset(&config, 0, sizeof(config)); + memset(&ctx, 0, sizeof(ctx)); + + ctx.config = &config; + + config.fips_mode = FLB_FALSE; + default_id = azb_block_blob_id_blob(&ctx, "blob/path.log", 1); + TEST_CHECK(default_id != NULL); + if (default_id == NULL) { + return; + } + + config.fips_mode = FLB_TRUE; + fips_id = azb_block_blob_id_blob(&ctx, "blob/path.log", 1); + TEST_CHECK(fips_id != NULL); + if (fips_id == NULL) { + flb_free(default_id); + return; + } + + TEST_CHECK(strlen(default_id) == 64); + TEST_CHECK(strlen(fips_id) == 64); + TEST_CHECK(strcmp(default_id, fips_id) != 0); + + flb_free(default_id); + flb_free(fips_id); +} + TEST_LIST = { {"resolve_path_basic_tag", test_resolve_path_basic_tag}, {"resolve_path_custom_delimiter", test_resolve_path_custom_delimiter}, @@ -491,5 +527,6 @@ TEST_LIST = { {"commit_prefix_fallback_static_path", test_commit_prefix_fallback_static_path}, {"uri_create_static_prefix_fallback", test_uri_create_static_prefix_fallback}, {"block_blob_commit_requires_suffix", test_block_blob_commit_requires_suffix}, + {"block_blob_id_uses_sha256_in_fips_mode", test_block_blob_id_uses_sha256_in_fips_mode}, {0} }; From b2d97ad5ed46f23a1aeae9fca2da5779f9ebcd2b Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Wed, 1 Jul 2026 17:48:25 +0900 Subject: [PATCH 8/8] tests: internal: Compute an expected sha256 hash Signed-off-by: Hiroshi Hatake --- tests/internal/azure_blob_path.c | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/internal/azure_blob_path.c b/tests/internal/azure_blob_path.c index 7d668292e48..58c95f51062 100644 --- a/tests/internal/azure_blob_path.c +++ b/tests/internal/azure_blob_path.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "../../plugins/out_azure_blob/azure_blob.h" #include "../../plugins/out_azure_blob/azure_blob_uri.h" @@ -481,8 +483,16 @@ void test_block_blob_commit_requires_suffix(void) void test_block_blob_id_uses_sha256_in_fips_mode(void) { + int i; + int ret; + int len; struct flb_config config; struct flb_azure_blob ctx; + unsigned char sha256[32] = {0}; + char digest_hex[33] = {0}; + char expected_plain[128]; + char expected_id[65]; + size_t expected_id_len; char *default_id; char *fips_id; @@ -510,6 +520,43 @@ void test_block_blob_id_uses_sha256_in_fips_mode(void) TEST_CHECK(strlen(fips_id) == 64); TEST_CHECK(strcmp(default_id, fips_id) != 0); + ret = flb_hash_simple(FLB_HASH_SHA256, (unsigned char *) "blob/path.log", + strlen("blob/path.log"), sha256, sizeof(sha256)); + TEST_CHECK(ret == 0); + if (ret != 0) { + flb_free(default_id); + flb_free(fips_id); + return; + } + + for (i = 0; i < 16; i++) { + snprintf(digest_hex + (i * 2), 3, "%02x", sha256[i]); + } + + len = snprintf(expected_plain, sizeof(expected_plain), "%s.flb-part.%06d", + digest_hex, 1); + TEST_CHECK(len > 0); + TEST_CHECK(len < sizeof(expected_plain)); + if (len <= 0 || len >= sizeof(expected_plain)) { + flb_free(default_id); + flb_free(fips_id); + return; + } + + ret = flb_base64_encode((unsigned char *) expected_id, sizeof(expected_id), + &expected_id_len, (unsigned char *) expected_plain, + len); + TEST_CHECK(ret == 0); + TEST_CHECK(expected_id_len == 64); + if (ret != 0 || expected_id_len >= sizeof(expected_id)) { + flb_free(default_id); + flb_free(fips_id); + return; + } + + expected_id[expected_id_len] = '\0'; + TEST_CHECK(strcmp(fips_id, expected_id) == 0); + flb_free(default_id); flb_free(fips_id); }