enhance: enable OpenSSL FIPS mode for Milvus (#48331)

Layer 2 (OpenSSL FIPS) changes:
- Add programmatic FIPS activation via OSSL_LIB_CTX_load_config in
boring_enabled.go (gated by //go:build boringcrypto)
- Add openssl-fips.cnf with fips + default providers and
default_properties = fips=yes
- Use absolute .include path for fipsmodule.cnf — OpenSSL resolves
relative .include from the process working directory, not the config
file's directory, causing silent FIPS provider load failure
- Add RAND_bytes probe after config load to verify the FIPS provider is
truly functional (EVP_default_properties_is_fips_enabled only checks the
property string, not whether the provider loaded)
- Dockerfiles: add openssl fipsinstall + OPENSSL_MODULES env var
- Log OpenSSL FIPS status from C++ via
EVP_default_properties_is_fips_enabled

Layer 1 (Go BoringCrypto) changes:
- Add GOEXPERIMENT=boringcrypto build flag (conditional on
MILVUS_FIPS_ENABLED=ON)
- Add boringEnabled() build-tagged functions for startup logging

s2n-tls upgrade:
- Override s2n 1.4.1 (from aws-c-io) to 1.6.0 in conanfile.py. s2n 1.4.1
only detects FIPS via the legacy OPENSSL_FIPS define (not set by OpenSSL
3.x). s2n 1.6.0 adds EVP_default_properties_is_fips_enabled() detection
so s2n enters FIPS mode and uses RAND_bytes() through the FIPS provider.

See also: #48202, #48301

Signed-off-by: yangxuan <xuan.yang@zilliz.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
XuanYang-cn
2026-03-23 15:09:28 +08:00
committed by GitHub
co-authored by Claude Opus 4.6
parent ebb648f647
commit c54b34a880
15 changed files with 140 additions and 2 deletions
+7 -1
View File
@@ -57,6 +57,12 @@ use_opendal = OFF
ifdef USE_OPENDAL
use_opendal = ${USE_OPENDAL}
endif
# FIPS: default OFF. Set MILVUS_FIPS_ENABLED=ON to enable BoringCrypto.
GOEXPERIMENT_FLAG :=
ifeq ($(MILVUS_FIPS_ENABLED),ON)
GOEXPERIMENT_FLAG := GOEXPERIMENT=boringcrypto
endif
# golangci-lint
GOLANGCI_LINT_VERSION := 1.64.7
GOLANGCI_LINT_OUTPUT := $(shell $(INSTALL_PATH)/golangci-lint --version 2>/dev/null)
@@ -106,7 +112,7 @@ build-go:
@echo "Building Milvus ..."
@source $(PWD)/scripts/setenv.sh && \
mkdir -p $(INSTALL_PATH) && go env -w CGO_ENABLED="1" && \
CGO_LDFLAGS="$${CGO_LDFLAGS} $(CGO_LDFLAGS)" CGO_CFLAGS="$${CGO_CFLAGS} $(CGO_CFLAGS)" GO111MODULE=on $(GO) build -pgo=$(PGO_PATH)/default.pgo -ldflags="-r $${RPATH} -X '$(OBJPREFIX).BuildTags=$(BUILD_TAGS)' -X '$(OBJPREFIX).BuildTime=$(BUILD_TIME)' -X '$(OBJPREFIX).GitCommit=$(GIT_COMMIT)' -X '$(OBJPREFIX).GoVersion=$(GO_VERSION)' -X '$(OBJPREFIX).MilvusVersion=$(MILVUS_VERSION)'" \
$(GOEXPERIMENT_FLAG) CGO_LDFLAGS="$${CGO_LDFLAGS} $(CGO_LDFLAGS)" CGO_CFLAGS="$${CGO_CFLAGS} $(CGO_CFLAGS)" GO111MODULE=on $(GO) build -pgo=$(PGO_PATH)/default.pgo -ldflags="-r $${RPATH} -X '$(OBJPREFIX).BuildTags=$(BUILD_TAGS)' -X '$(OBJPREFIX).BuildTime=$(BUILD_TIME)' -X '$(OBJPREFIX).GitCommit=$(GIT_COMMIT)' -X '$(OBJPREFIX).GoVersion=$(GO_VERSION)' -X '$(OBJPREFIX).MilvusVersion=$(MILVUS_VERSION)'" \
-tags $(MILVUS_GO_BUILD_TAGS) -o $(INSTALL_PATH)/milvus $(PWD)/cmd/main.go 1>/dev/null
milvus-gpu: build-cpp-gpu print-gpu-build-info
@@ -28,11 +28,15 @@ COPY --chown=root:root --chmod=774 ./configs/ /milvus/configs/
COPY --chown=root:root --chmod=774 ./lib/ /milvus/lib/
ENV PATH=/milvus/bin:$PATH
ENV LD_LIBRARY_PATH=/milvus/lib:$LD_LIBRARY_PATH:/usr/lib
ENV LD_PRELOAD=${MILVUS_ASAN_LIB}:/milvus/lib/libjemalloc.so
ENV MALLOC_CONF=background_thread:true
ENV OPENSSL_MODULES=/milvus/lib/ossl-modules
# Generate fipsmodule.cnf for FIPS module integrity self-test.
# FIPS activation is handled programmatically at startup — no OPENSSL_CONF needed.
RUN openssl fipsinstall -out /milvus/configs/ssl/fipsmodule.cnf -module /milvus/lib/ossl-modules/fips.so
# Change user to milvus
# protobuf 5.x RepeatedField adds container annotations that trigger ASAN
@@ -27,6 +27,11 @@ ENV PATH=/milvus/bin:$PATH
ENV LD_LIBRARY_PATH=/milvus/lib:$LD_LIBRARY_PATH:/usr/lib
ENV LD_PRELOAD=/milvus/lib/libjemalloc.so
ENV MALLOC_CONF=background_thread:true
ENV OPENSSL_MODULES=/milvus/lib/ossl-modules
# Generate fipsmodule.cnf for FIPS module integrity self-test.
# FIPS activation is handled programmatically at startup — no OPENSSL_CONF needed.
RUN openssl fipsinstall -out /milvus/configs/ssl/fipsmodule.cnf -module /milvus/lib/ossl-modules/fips.so
# Change user to milvus
RUN groupadd -r milvus && useradd -r -g milvus milvus && \
@@ -36,6 +36,11 @@ ENV PATH=/milvus/bin:$PATH
ENV LD_LIBRARY_PATH=/milvus/lib:$LD_LIBRARY_PATH:/usr/lib
ENV LD_PRELOAD=${MILVUS_ASAN_LIB}:/milvus/lib/libjemalloc.so
ENV MALLOC_CONF=background_thread:true
ENV OPENSSL_MODULES=/milvus/lib/ossl-modules
# Generate fipsmodule.cnf for FIPS module integrity self-test.
# FIPS activation is handled programmatically at startup — no OPENSSL_CONF needed.
RUN openssl fipsinstall -out /milvus/configs/ssl/fipsmodule.cnf -module /milvus/lib/ossl-modules/fips.so
# Change user to milvus
# protobuf 5.x RepeatedField adds container annotations that trigger ASAN
@@ -41,6 +41,11 @@ ENV PATH=/milvus/bin:$PATH
ENV LD_LIBRARY_PATH=/milvus/lib:$LD_LIBRARY_PATH:/usr/lib
ENV LD_PRELOAD=${MILVUS_ASAN_LIB}:/milvus/lib/libjemalloc.so
ENV MALLOC_CONF=background_thread:true
ENV OPENSSL_MODULES=/milvus/lib/ossl-modules
# Generate fipsmodule.cnf for FIPS module integrity self-test.
# FIPS activation is handled programmatically at startup — no OPENSSL_CONF needed.
RUN openssl fipsinstall -out /milvus/configs/ssl/fipsmodule.cnf -module /milvus/lib/ossl-modules/fips.so
# Change user to milvus
# protobuf 5.x RepeatedField adds container annotations that trigger ASAN
+9
View File
@@ -0,0 +1,9 @@
//go:build !boringcrypto
package milvus
func boringEnabled() bool {
return false
}
func maybeEnableOpenSSLFIPS() {}
+57
View File
@@ -0,0 +1,57 @@
//go:build boringcrypto
package milvus
/*
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/provider.h>
#include <openssl/rand.h>
static int enableOpenSSLFIPS() {
unsigned char buf[1];
if (!OSSL_LIB_CTX_load_config(NULL, "/milvus/configs/ssl/openssl-fips.cnf")) {
return -1; // config load failed
}
if (!EVP_default_properties_is_fips_enabled(NULL)) {
return 0; // config loaded but fips=yes not set
}
// EVP_default_properties_is_fips_enabled only checks the property string,
// not whether the FIPS provider is actually loaded. Verify by checking
// that RAND_bytes works (requires a working FIPS DRBG).
if (RAND_bytes(buf, 1) != 1) {
return -2; // FIPS property set but provider not functional
}
return 1; // FIPS truly enabled and functional
}
*/
import "C"
import (
"crypto/boring"
"log"
"sync"
)
func boringEnabled() bool {
return boring.Enabled()
}
var fipsOnce sync.Once
func maybeEnableOpenSSLFIPS() {
fipsOnce.Do(func() {
rc := C.enableOpenSSLFIPS()
switch rc {
case 1:
log.Println("OpenSSL FIPS mode enabled")
case 0:
log.Println("WARNING: OpenSSL FIPS config loaded but fips=yes not set in default properties")
case -2:
log.Println("FATAL: OpenSSL FIPS property set but FIPS provider not functional (check OPENSSL_MODULES env var and .include path in openssl-fips.cnf)")
default:
log.Println("Failed to load OpenSSL FIPS config")
}
})
}
+2
View File
@@ -37,6 +37,7 @@ func (c *run) execute(args []string, flags *flag.FlagSet) {
runtimeDir := createRuntimeDir(serverType)
filename := getPidFileName(serverType, roles.Alias)
maybeEnableOpenSSLFIPS()
c.printBanner(flags.Output())
c.injectVariablesToEnv()
c.printHardwareInfo(flags.Output())
@@ -60,6 +61,7 @@ func (c *run) printBanner(w io.Writer) {
fmt.Fprintln(w, "Built: "+BuildTime)
fmt.Fprintln(w, "GitCommit: "+GitCommit)
fmt.Fprintln(w, "GoVersion: "+GoVersion)
fmt.Fprintf(w, "Milvus FIPS in Go: BoringCrypto %v\n", boringEnabled())
fmt.Fprintln(w)
metrics.BuildInfo.WithLabelValues(getEffectiveVersion(), BuildTime, GitCommit).Set(1)
}
+21
View File
@@ -0,0 +1,21 @@
config_diagnostics = 1
openssl_conf = openssl_init
.include /milvus/configs/ssl/fipsmodule.cnf
[openssl_init]
providers = provider_sect
alg_section = algorithm_sect
[provider_sect]
fips = fips_sect
default = default_sect
[fips_sect]
activate = 1
[default_sect]
activate = 1
[algorithm_sect]
default_properties = fips=yes
+3
View File
@@ -111,6 +111,9 @@ class MilvusConan(ConanFile):
if self.settings.os != "Macos":
self.requires("libunwind/1.8.1#97965ef7da98cf1662e14219b14134f7")
self.requires("aws-sdk-cpp/1.11.692@milvus/dev#1e17deac19383217d291a01c23147b33")
# Override s2n 1.4.1 (from aws-c-io) to 1.6.0 for OpenSSL 3.x FIPS detection
if self.settings.os in ["Linux", "FreeBSD"]:
self.requires("s2n/1.6.0")
def imports(self):
self.copy("*.dylib", "../lib", "lib")
+12
View File
@@ -17,6 +17,8 @@
#include <cstddef>
#include <mutex>
#include <openssl/evp.h>
#include "common/init_c.h"
#include "common/Common.h"
#include "common/Tracer.h"
#include "common/init_c.h"
@@ -25,6 +27,7 @@
std::once_flag traceFlag;
std::once_flag cpuNumFlag;
std::once_flag fipsFlag;
void
InitCpuNum(const int value) {
@@ -102,6 +105,15 @@ SetExprResCacheCapacityBytes(int64_t bytes) {
static_cast<size_t>(bytes));
}
void
LogOpenSSLFIPSStatus() {
std::call_once(fipsFlag, []() {
LOG_INFO("Milvus FIPS in OpenSSL: {}",
EVP_default_properties_is_fips_enabled(NULL) ? "enabled"
: "disabled");
});
}
void
InitTrace(CTraceConfig* config) {
auto traceConfig = milvus::tracer::TraceConfig{config->exporter,
+4
View File
@@ -71,6 +71,10 @@ InitTrace(CTraceConfig* config);
void
SetTrace(CTraceConfig* config);
// OpenSSL FIPS status
void
LogOpenSSLFIPSStatus();
// Expr result cache
void
SetExprResCacheEnable(bool val);
+2
View File
@@ -44,6 +44,8 @@ func InitSegcore(nodeID int64) error {
C.IndexBuilderInit(cGlogConf)
C.free(unsafe.Pointer(cGlogConf))
C.LogOpenSSLFIPSStatus()
// update log level based on current setup
initcore.UpdateLogLevel(paramtable.Get().LogCfg.Level.GetValue())
+2
View File
@@ -65,6 +65,8 @@ func doInitQueryNodeOnce(ctx context.Context) error {
C.SegcoreInit(cGlogConf)
C.free(unsafe.Pointer(cGlogConf))
C.LogOpenSSLFIPSStatus()
// update log level based on current setup
UpdateLogLevel(paramtable.Get().LogCfg.Level.GetValue())
+1
View File
@@ -23,6 +23,7 @@ mkdir -p "$LIBRARY_PATH"
cp $PWD"/internal/core/output/lib/"*.dylib* "$LIBRARY_PATH" 2>/dev/null || true
cp $PWD"/internal/core/output/lib/"*.so* "$LIBRARY_PATH" || true
cp $PWD"/internal/core/output/lib64/"*.so* "$LIBRARY_PATH" 2>/dev/null || true
cp -r $PWD"/internal/core/output/lib/ossl-modules" "$LIBRARY_PATH" 2>/dev/null || true
for LIB_PATH in $(ldd ./bin/milvus | grep -E '(asan|atomic)' | awk '{print $3}'); do
cp "$LIB_PATH" "$LIBRARY_PATH" 2>/dev/null