| title | Build the FIPS variant | ||||
|---|---|---|---|---|---|
| description | Build `pg_hardstorage` against Go's BoringCrypto (FIPS 140-2 validated module). | ||||
| tags |
|
Compile a
pg_hardstorage-fipsbinary that routes everycrypto/tls,crypto/aes,crypto/sha256, … call through Google's FIPS 140-2 validated BoringCrypto module. CGO required; Linux/amd64 only.
-
Go 1.26+ (the version pinned in
go.mod).GOEXPERIMENT=boringcryptois built into the upstream Go toolchain onlinux/amd64; on every other GOOS/GOARCH the experiment fails with a clear error. -
A C toolchain reachable to cgo. On Debian:
sudo apt install build-essential
-
Linux/amd64 build host (BoringSSL doesn't have a validated build for ARM or other arches).
make build-fipsEquivalent direct invocation:
GOEXPERIMENT=boringcrypto CGO_ENABLED=1 \
go build -tags fips \
-trimpath \
-ldflags '-s -w
-X github.com/cybertec-postgresql/pg_hardstorage/internal/version.Version=$(VERSION)
-X github.com/cybertec-postgresql/pg_hardstorage/internal/version.Commit=$(COMMIT)
-X github.com/cybertec-postgresql/pg_hardstorage/internal/version.Date=$(DATE)' \
-o bin/pg_hardstorage-fips \
./cmd/pg_hardstorageThe fips build tag is the runtime selector:
internal/fips.Enabled() returns true in this flavour.
The pg_hardstorage version subcommand surfaces the variant
so operators see at a glance which flavour is running.
go tool nm bin/pg_hardstorage-fips | grep -i goboringcrypto | head -50000000000abc123 T crypto/internal/boring._cgo_4ad7b8e0f3c5_Cfunc__goboringcrypto_AES_set_decrypt_key
0000000000abc456 T crypto/internal/boring._cgo_4ad7b8e0f3c5_Cfunc__goboringcrypto_AES_set_encrypt_key
...The symbols' presence is your "yes, this binary actually
routes through BoringCrypto" check. Empty output means the
build silently fell back to Go's default crypto stack —
verify GOEXPERIMENT=boringcrypto was set during the build.
The version subcommand surfaces the variant:
./bin/pg_hardstorage-fips versionpg_hardstorage v1.0.x [FIPS] (abcdef1, built 2026-01-02T03:04:05Z)The [FIPS] marker in the one-line output is your runtime
confirmation. The JSON form (version --output json) carries
"variant": "fips" and "fips": true.
GOEXPERIMENT=boringcrypto swaps Go's standard crypto
implementations for BoringCrypto-backed equivalents at
compile time. The substitution is automatic and exhaustive
within the standard library: every crypto/tls,
crypto/aes, crypto/sha256, crypto/hmac, crypto/rsa,
crypto/ecdsa call routes through validated code.
Algorithms BoringCrypto doesn't validate (e.g. chacha20poly1305
in older versions) refuse at runtime under
internal/fips.Enabled() rather than silently fall back.
The fips build tag activates the project's own FIPS
posture: refuses non-FIPS encryption providers, refuses
unsigned manifests in compliance mode, and surfaces the
variant in version output.
| Surface | Behaviour |
|---|---|
| Storage envelope | AES-256-GCM-SIV via BoringCrypto. |
| TLS to control plane / repos | Only FIPS-approved ciphersuites. |
| KMS providers | Refuses providers that aren't FIPS-approved. |
version |
Prints the [FIPS] marker (JSON variant: "fips", fips: true). |
| Unit / integration tests | Same suite, run with the FIPS build. |
Operators who don't need FIPS should stay on the default
build (make build). The FIPS variant is for regulated
environments where the validated-module requirement is the
deciding factor.
The packaging story is roadmap from the SPEC:
| Lands | Posture |
|---|---|
| v0.5 | pg-hardstorage-fips .deb / .rpm shipped with |
goreleaser; Conflicts: pg-hardstorage on Debian so the |
|
| two binaries don't co-install. | |
| v0.5+ | A distroless FIPS container image, cosign-signed, |
SBOM via syft. Not yet published — no -fips image |
|
| variant exists today; only the default | |
ghcr.io/cybertec-postgresql/pg_hardstorage image is |
|
| published, and it is not FIPS-built. |
For v0.1 the path is "build it yourself with the instructions on this page."
You're on a non-linux/amd64 host. The experiment is only
available on linux/amd64; cross-build to that arch from
elsewhere or run the build on a real Linux/amd64 box.
Install a C toolchain (build-essential on Debian,
Development Tools on Fedora). FIPS requires cgo because
BoringSSL is C; the wrapper links it in.
The build fell back to Go's default crypto stack. Causes:
GOEXPERIMENTenv var didn't reach the build (check withgo env GOEXPERIMENTfrom the same shell).CGO_ENABLED=0overrode cgo. The Makefile target setsCGO_ENABLED=1explicitly; if you're callinggo builddirectly, set it yourself.
Expected behaviour. The FIPS variant is a closed set of validated algorithms; the project refuses anything outside that set rather than silently falling back. If your deployment depends on a non-FIPS algorithm you can't run on the FIPS variant.
- Build from source — the default build the FIPS variant deviates from.
- Build the PKCS#11 variant — the other CGO-using flavour.
- Compliance mapping — how the FIPS posture maps to control frameworks (SOC2, ISO, HIPAA, PCI, FedRAMP).