Creating FIPS-Compliant ClickHouse® Builds

TL;DR: Altinity provides a FIPS-compatible ClickHouse 25.3 build for environments where FIPS requirements apply. The build uses AWS-LC FIPS and updates dependencies including the Azure SDK, krb5, and MongoDB driver to work with the FIPS library, while features that cannot be used in the FIPS build are disabled. The build is tested and validated for FIPS-compatible operation.
In April 2026, we released the FIPS build of ClickHouse 25.3.8. In this blog post, we will walk you through the challenges we faced along the way.
What is FIPS?
FIPS 140 is a U.S. government standard for cryptographic modules. Organizations in regulated industries (government, finance, healthcare) often require that all cryptographic operations go through a FIPS-validated module. A FIPS build of ClickHouse means that all TLS connections, encryption at rest, and authentication hashing use a certified cryptographic library instead of a generic one.
Altinity maintains FIPS builds of ClickHouse for customers who operate under these compliance requirements. A regular ClickHouse build already encrypts data in transit and at rest, but the cryptographic library it ships with has not gone through the FIPS validation process. The FIPS build replaces it with one that has.
Picking a cryptographic library
Our previous FIPS build was 24.3.5.48, released in September 2024. It used BoringSSL as its cryptographic module, validated under FIPS 140-2 (Security Policy #4407). The build was AMD64-only.
Starting with upstream ClickHouse 24.4, BoringSSL was replaced with OpenSSL 3.2. This meant we could no longer simply carry BoringSSL forward into newer ClickHouse versions without maintaining a growing pile of patches. It also introduced a measurable SSL performance regression in the upstream builds.
For the 25.3 FIPS build, we had three requirements: upgrade from FIPS 140-2 to 140-3 (the newer revision of the standard), recover the SSL performance lost in the OpenSSL switch, and add ARM (Aarch64) support. AWS-LC FIPS 2.0.0, a general-purpose cryptographic library maintained by the AWS Cryptography team, checked all three boxes. It descends from BoringSSL, includes performance-optimized assembly for both x86-64 and ARM, and was validated under FIPS 140-3 in October 2024.
We benchmarked ClickHouse encryption operations across all supported cipher modes, comparing three builds: 24.3 stable (BoringSSL), 25.3 stable (OpenSSL 3.2), and 25.3 FIPS (AWS-LC). Here are the results for a few representative modes:
| Cipher mode | 24.3 stable | 25.3 stable | 25.3 FIPS |
| AES-256-GCM | 10.3 s | 54.8 s (5.3×) | 20.7 s (2.0×) |
| AES-256-CBC | 4.1 s | 49.2 s (12.0×) | 8.1 s (2.0×) |
| AES-256-CTR | 3.5 s | 47.5 s (13.6×) | 7.9 s (2.3×) |
The multipliers are relative to 24.3 stable. The upstream 25.3 build is 5 to 13 times slower than the old 24.3, depending on the cipher mode. The FIPS build with AWS-LC closes most of that gap, staying within about 2× of the original BoringSSL performance while being 3 to 6 times faster than the current upstream OpenSSL build.
Building the FIPS server
With the library chosen, the next step was integrating AWS-LC into the ClickHouse build and making everything work with it.
Getting it built
After adding AWS-LC to the ClickHouse build system, we had to fix every place where the code relied on OpenSSL 3 APIs that AWS-LC doesn’t provide. ClickHouse and its dependencies now target the OpenSSL 3 API, while AWS-LC exposes the older 1.1.1-style API. There were some breaking changes, so we didn’t expect a smooth ride.
To make the process simpler for us, we disabled every 3rd party library at first (using the ‑DENABLE_LIBRARIES=0 configuration flag) to see where it would fail. It did fail in a couple of places due to missing or incompatible function signatures. To fix this, we introduced evp_API_shim.h and injected it into any component that would depend on the OpenSSL target.
Enabling features
After getting the basics done, we started carefully enabling the dependencies one by one and checking that:
- The build succeeds
- ClickHouse runs without crashes
- The features corresponding to the library work properly
Many of the dependencies were straightforward and worked the same way as in the original 25.3.8, including full support for:
- S3
- Azure Blob Storage (via an Altinity fork of azure-sdk-for-cpp, see below)
- gRPC
- Parquet
- Kafka, NATS, MySQL, MongoDB
- Cassandra, AMQP
Some of these required changes in evp_API_shim.h or in the configuration files of the corresponding libraries. Two required us to fork them to patch the source code directly, and one more needed non-trivial fixes.
azure-sdk-for-cpp
We forked azure-sdk-for-cpp in order to fix the build. Originally, the build failed due to the header <openssl/ocsp.h> being missing from AWS-LC. This header was used by Azure SDK for C++ to implement the certificate revocation checking. It is only enabled when EnableCertificateRevocationListCheck is explicitly set to true in CurlTransportSslOptions (default false), which ClickHouse never does.
krb5
krb5 was also forked to build against AWS-LC and to disable non-FIPS-approved ciphers (Camellia, DES/3DES). As a consequence, Kerberos authentication in the FIPS build requires the KDC to support AES encryption types (aes256-cts-hmac-sha1-96 or aes128-cts-hmac-sha1-96). A KDC configured with only DES or 3DES will not work.
MongoDB driver
The MongoDB C driver did not require a fork, but its TLS integration needed three non-trivial fixes in evp_API_shim.h. All three stemmed from subtle behavioral differences between OpenSSL and AWS-LC that are invisible at the API level: BIO_get_ssl silently returned an uninitialized pointer because AWS-LC’s BIO ctrl handler doesn’t support the expected control code, BIO_do_handshake did nothing because neither the state machine dispatch nor the transport BIO connection worked as in OpenSSL, and X509_VERIFY_PARAM_set1_host with a zero-length name poisoned certificate verification entirely. Without these fixes, any MongoDB TLS connection would have failed or crashed.
With these forks and fixes in place, we eventually managed to build with ‑DENABLE_LIBRARIES=1, but kept ‑DENABLE_RUST=0. As a result, three ClickHouse features are unavailable in the FIPS build:
DeltaLaketable engine and thedeltaLake()table function- PRQL query language
- Skim interactive search in
clickhouse-client
The Rust-dependent components used by these features are not currently supported in this FIPS build.
Testing
At some point we noticed that a test for the MergeTree encryption codec was failing. It turns out AES_128_GCM_SIV and AES_256_GCM_SIV are not FIPS-approved. We replaced them with their FIPS-approved counterparts: AES_128_GCM and AES_256_GCM.
This is a breaking change for anyone using columns using these encryption codecs. The FIPS build uses different on-disk byte codes deliberately, so that attempting to read SIV-encrypted data on a FIPS build produces an immediate error rather than silent corruption. The DDL codec names and config section names change as well:
| Non-FIPS build | FIPS build | |
| DDL codec | AES_128_GCM_SIV / AES_256_GCM_SIV | AES_128_GCM / AES_256_GCM |
| Config section | <aes_128_gcm_siv> | <aes_128_gcm> |
| On-disk byte codes | 0x96 / 0x97 | 0xFA / 0xFB |
If you are migrating from a non-FIPS build and use encrypted columns, you must decrypt the data before upgrading, update the config, and re-encrypt after switching to the FIPS binary.
FIPS validation
We embedded AWS-LC’s SSL conformance and ACVP validation harnesses directly into the FIPS binary (clickhouse ssl-shim, clickhouse ssl-handshaker, clickhouse acvp-server). This lets us run the full suite of 8,037 TLS conformance tests and 31 ACVP cryptographic algorithm suites against the exact binary that ships to customers, not just a standalone reference build of the crypto library.
Housekeeping
We also had quite a bit of housekeeping, including but not limited to:
- Introducing a new
<cipherSuites>config element to control TLS 1.3 ciphers — the existing <cipherList> only governs TLS 1.2 and below. The default restricts TLS 1.3 toTLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256, excludingTLS_CHACHA20_POLY1305_SHA256, which is not FIPS-approved - Fixing ClickHouse Keeper to respect
<cipherList>,<cipherSuites>,<dhParamsFile>, and<ecdhCurve>from config — previously Keeper’s TLS setup silently ignored these settings - Fixing
disableProtocolsto actually handletlsv1_3, which was silently ignored before, making it impossible to disable TLS 1.3 via configuration - Adding startup checks that expose FIPS mode, known-answer-test results, and integrity-check results
- Adding
FIPS_CLICKHOUSEto thesystem.build_optionstable and fixingOPENSSL_VERSIONandOPENSSL_IS_BORING_SSL, which were showing blank in FIPS builds - Switching PostgreSQL’s internal hash backend to delegate through AWS-LC so that authentication hashing (
SCRAM-SHA-256,MD5) goes through the FIPS-validated module instead of PostgreSQL’s own software implementation - Removing the default upstream Sentry endpoint and removing Docker build fallbacks that install upstream ClickHouse packages
You can read the full changelog to get more details.
Summary
The altinityfips builds give ClickHouse users in government, finance, healthcare, and other industries a FIPS-compatible option. Our efforts in modifying the ClickHouse build process and forking or fixing the required libraries and tools are another example of Altinity’s commitment to building the solutions our customers need.
ClickHouse® is a registered trademark of ClickHouse, Inc.; Altinity is not affiliated with or associated with ClickHouse, Inc.