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
4 changes: 4 additions & 0 deletions include/fluent-bit/flb_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions include/fluent-bit/flb_fips.h
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions plugins/out_azure_blob/azure_blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
85 changes: 64 additions & 21 deletions plugins/out_azure_blob/azure_blob_blockblob.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <fluent-bit/flb_crypto_constants.h>
#include <fluent-bit/flb_compression.h>

#include <string.h>
#include <math.h>

#include "azure_blob.h"
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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, "<Uncommitted>", 13);
Expand Down
8 changes: 7 additions & 1 deletion plugins/out_s3/s3.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions src/flb_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)},
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions src/flb_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <fluent-bit/flb_utils.h>
#include <fluent-bit/flb_config.h>
#include <fluent-bit/flb_engine.h>
#include <fluent-bit/flb_fips.h>
#include <fluent-bit/flb_event.h>
#include <fluent-bit/flb_engine_dispatch.h>
#include <fluent-bit/flb_network.h>
Expand Down Expand Up @@ -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);
}
Expand Down
100 changes: 100 additions & 0 deletions src/flb_fips.c
Original file line number Diff line number Diff line change
@@ -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 <fluent-bit/flb_info.h>
#include <fluent-bit/flb_config.h>
#include <fluent-bit/flb_fips.h>

#ifdef FLB_HAVE_OPENSSL
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/opensslv.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#include <openssl/provider.h>
#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);
Comment thread
cosmo0920 marked this conversation as resolved.
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
}
Loading
Loading