VeilNet

FIPS

Learn which parts of the guardian use FIPS 140-3 validated cryptography, and how to build and use the FIPS base.

Validation by Part

The guardian's application-layer cryptography runs through modules validated under FIPS 140-3. Validation applies to a module, not to a whole system, so the guardian states its position part by part:

PartPosition
Identity serviceAlways runs in strict FIPS mode with its own validated provider, whichever base you choose. It hashes passwords and signs sign-in tokens. Passwords are hashed with PBKDF2-HMAC-SHA512 at 210,000 iterations.
API server and consoleValidated on the FIPS base. Their three cryptographic operations are TLS, token signature checks and AES-256-GCM sealing. On the FIPS base, all three run inside OpenSSL FIPS Provider 3.1.2. On the default base, they do not.
State and audit storeUses the same validated provider.
SignerSigns credentials with ML-DSA, the FIPS 204 algorithm. See Protecting the Signer.
Host kernelYour responsibility. Whether to use a validated kernel is your procurement decision.

The provider is OpenSSL FIPS Provider 3.1.2, certificate #4985. It is validated under FIPS 140-3 until 10 March 2030.

Using the FIPS Base

The default NODE_BASE, node:24-trixie-slim, cannot perform validated cryptography, however you configure it. The FIPS base compiles OpenSSL and Node.js from source, which takes 30 to 60 minutes. Build it once as a release job, not during a deployment.

0 of 3 done
  1. $ ./build-node-fips.sh --tag registry.example.gov/node-fips:24.21.0 --push

    --push needs a tag that includes a registry path. Before it pushes, the script checks that Node.js is built against the validated provider. It refuses to push an image that is not.

    The script also warns if its pinned Node.js version is no longer the newest Active LTS release, then builds anyway:

    warn node-fips/Dockerfile pins 24.21.0, but the newest Active LTS is …
        Bump NODE_VERSION and NODE_SHA256 together, and the stock base with them:
        …
        Building anyway.

    If the host has no route out, the script says that it is skipping this check. Neither case stops the build.

Protecting the Signer

The signer signs realm and machine credentials with ML-DSA, the algorithm that FIPS 204 specifies. Every anchor checks these signatures at every handshake, so the guardian keeps the signer isolated:

  • The signer's keys are sealed at rest with AES-256-GCM through the validated provider. The signer receives a seed for one signature only, and writes it nowhere.
  • The signer joins no network. It has no listener, no realm and no peers. Only the API server can reach it, with a token that changes each time the signer starts.
  • The admin nodes run the same daemon with credential signing turned off. They hold no key except their own identity.
  • The binaries are owned by root, and the account that runs them cannot change them. The image build rejects a control tool that can mint a realm root.

Testing on a FIPS-mode Host

A container takes its FIPS mode from the host kernel, and brings its own cryptographic library. Test the deployment on a FIPS-mode host before you call it ready.

Any image you add to the stack must carry its own provider. Otherwise, opt the image out with OPENSSL_FORCE_FIPS_MODE=0 and record a written justification.

Verifying a Deployment

On the FIPS base, list the providers that the API server's OpenSSL loads:

$ docker compose exec api /opt/openssl/bin/openssl list -providers

The output must include OpenSSL FIPS Provider. Keep it with your accreditation evidence.

The FIPS base fails its own build if the provider is not active. The identity service refuses to start in strict FIPS mode without its provider. Neither can fall back silently. For what else you must confirm yourself, see Host Requirements.