Repository navigation
FIPS Mode
Run UCM's cryptography in the validated OpenSSL FIPS Provider.
Version: 2.241 (preview)
Status: 🧪 Preview, Docker image -fips, DEB and RPM packages built on a FIPS host
When deployed as documented on this page, UCM runs its cryptography in the validated OpenSSL FIPS Provider (OpenSSL FIPS Provider 3.1.2, CMVP certificate #4985). UCM itself is not validated: the validation covers the OpenSSL module, not UCM or its configuration.
FIPS mode is available from v2.241 as a preview. It needs two things:
| Piece | Role |
|---|---|
The -fips image (<version>-fips) |
Ships the 3.1.2 provider (fips.so) and links every library that uses OpenSSL (cryptography, psycopg2, xmlsec, Python's ssl and hashlib) to the system OpenSSL, so none carries its own copy |
UCM_FIPS=1 |
Turns FIPS mode on: the module is configured at start, checked, and UCM refuses what the module does not approve |
The same -fips image without UCM_FIPS runs in standard mode. The standard image with UCM_FIPS=1 refuses to start.
On RHEL 9 and Ubuntu 24.04 Pro, the DEB and RPM packages can instead run on the FIPS module of the host (see DEB and RPM packages).
- Image
neyslim/ultimate-ca-manager:<version>-fips(also onghcr.io/neyslim/ultimate-ca-manager), for amd64 and arm64.latest-fipsfollows the latest stable release -
UCM_FIPS=1(also accepted:true,yes,on) - A writable
/run/ucmfor the container user (uid 1000): the entrypoint writes the module configuration there at every start. The image provides it; with a read-only root filesystem (--read-only), mount a tmpfs there, and one on/tmp, which UCM needs for temporary files - The usual volumes:
/opt/ucm/dataand/etc/ucm(see Installation Guide)
docker run -d \
--name ucm \
-p 8443:8443 \
-p 8080:8080 \
-e UCM_FIPS=1 \
-v ucm-data:/opt/ucm/data \
-v ucm-config:/etc/ucm \
neyslim/ultimate-ca-manager:2.241-fips
# With a read-only root filesystem, add:
# --read-only --tmpfs /run/ucm:uid=1000 --tmpfs /tmpservices:
ucm:
image: neyslim/ultimate-ca-manager:2.241-fips
container_name: ucm
ports:
- "8443:8443"
- "8080:8080"
environment:
- UCM_FIPS=1
volumes:
- ucm-data:/opt/ucm/data
- ucm-config:/etc/ucm
# Only with a read-only root filesystem:
# read_only: true
# tmpfs:
# - /run/ucm:uid=1000
# - /tmp
volumes:
ucm-data:
ucm-config:helm install ucm ./charts/ucm --set fips.enabled=truefips.enabled: true adds the -fips suffix to the image tag (unless the tag already has it), sets UCM_FIPS=1 and mounts an in-memory volume on /run/ucm. The pod refuses to start if the provider is missing or fails its self-tests.
docker build --build-arg UCM_FIPS_BUILD=1 -t ucm:fips .
# or
./docker/build.sh --fipsThe build downloads openssl-3.1.2.tar.gz, checks its SHA-256, builds the provider with the commands of its security policy (./Configure enable-fips, make) and keeps only fips.so. It also compiles cryptography, psycopg2, lxml and xmlsec from source against the system libraries, and fails if any of them still bundles its own OpenSSL or libxml2. Expect a longer build than the standard image. docker/build.sh --fips tags the result <tag>-fips.
On a host in FIPS mode, the packages can use the FIPS module of the distribution instead of the 3.1.2 provider. Supported hosts: RHEL, AlmaLinux and Rocky Linux 9 (RPM ucm-el9-VERSION-1.el9.noarch.rpm) and Ubuntu 24.04 with Ubuntu Pro (sudo pro enable fips-updates, then reboot). With UCM_FIPS_BUILD=1, the package compiles cryptography, psycopg2, lxml and xmlsec against the system OpenSSL; other distributions refuse the option.
RHEL, AlmaLinux and Rocky Linux 9 (on RHEL, enable CodeReady Builder with sudo subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms instead of the first line):
sudo dnf config-manager --set-enabled crb
sudo dnf install -y python3.12-devel gcc pkgconf-pkg-config libpq-devel libxml2-devel libxslt-devel \
openssl-devel xmlsec1-devel xmlsec1-openssl libtool-ltdl-devel rust cargo
sudo install -d -m 750 /etc/ucm && echo 'UCM_FIPS_BUILD=1' | sudo tee /etc/ucm/ucm.env
sudo dnf install ./ucm-el9-VERSION-1.el9.noarch.rpmUbuntu 24.04 with Ubuntu Pro:
sudo apt-get install -y gcc pkg-config python3-dev python3-venv libpq-dev libxml2-dev libxslt1-dev \
zlib1g-dev libssl-dev libxmlsec1-dev libxmlsec1t64-openssl rustc-1.91 cargo-1.91
sudo install -d -m 750 /etc/ucm && echo 'UCM_FIPS_BUILD=1' | sudo tee /etc/ucm/ucm.env
sudo apt install ./ucm_VERSION_all.debThe first build takes about five minutes (log: /var/log/ucm/fips-build.log); later installs rebuild a package only when its version changed. When a tool is missing, the installation stops with the command to run and downloads nothing. On a host in FIPS mode, the package adds UCM_FIPS=1 to ucm.env (an explicit UCM_FIPS=0 is kept) and prints the readiness report. The built-in updater checks the build tools before each update and refuses it when one is missing.
The readiness check runs the same way on a native install:
cd /opt/ucm/backend && sudo -u ucm bash -c 'set -a; . /etc/ucm/ucm.env; set +a; /opt/ucm/venv/bin/python -m scripts.fips_preflight'With UCM_FIPS=1, the entrypoint and then the application check the module before anything is served:
-
Provider present: without
fips.soin the image (standard image), the container stops and says to use the-fipsvariant or removeUCM_FIPS -
/run/ucmwritable: otherwise the container stops and names the tmpfs to mount -
openssl fipsinstallruns on the machine at every start and writes the module configuration; it runs the module's self-tests, and a failure stops the container -
OpenSSL configuration:
fipsandbaseproviders,default_properties = fips=yes(approved algorithms only) -
Pre-checks: the
fipsprovider is active, MD5 is refused, SHA-256 works, and Python'shashlibruns on the provider -
Application checks: both
cryptographyandhashlibmust run on the FIPS provider, approved operations (ECDSA P-256, AES-GCM, PBKDF2) must work and refused ones (MD5, scrypt) must fail. Otherwise UCM logs the reason and exits
When everything passes, the log shows:
FIPS mode active: OpenSSL FIPS Provider 3.1.2 (library OpenSSL 3.5.x ...)
The entrypoint also forces HSM_AUTO_INIT=false: no default SoftHSM token is created in FIPS mode (see Limitations).
Health endpoint (no authentication):
curl -sk https://localhost:8443/api/v2/health
# {"status": "ok", ..., "fips_active": true}fips_active is true only when UCM_FIPS=1 is set and the provider is active.
Service status (authenticated): GET /api/v2/system/service/status includes a crypto block:
"crypto": {
"fips_requested": true,
"fips_active": true,
"provider_active": true,
"library": "OpenSSL 3.5.x ...",
"provider": {"name": "OpenSSL FIPS Provider", "version": "3.1.2", "buildinfo": "3.1.2"}
}From inside the container: the entrypoint sets OPENSSL_CONF for UCM's own process only, so name it in docker exec:
docker exec -e OPENSSL_CONF=/run/ucm/openssl-fips.cnf ucm openssl list -providers
# Providers:
# base
# name: OpenSSL Base Provider
# ...
# fips
# name: OpenSSL FIPS Provider
# version: 3.1.2
# status: active
docker exec -e OPENSSL_CONF=/run/ucm/openssl-fips.cnf ucm sh -c 'echo x | openssl md5'
# must fail: MD5 is not in the moduleA refused operation usually answers HTTP 400 with the problem type urn:ucm:problem:fips-restricted and a message of the form <feature> not available in FIPS mode; a few refusals give their own message (Argon2id restore, NTLM channel). Protocol endpoints answer in their own terms (SCEP badAlg, or 503 for a SCEP CA whose key is refused; OCSP unauthorized). In the web interface, forms stop offering what FIPS mode refuses: no Ed25519 for SSH CAs and keys, a FIPS rules notice on the Policies page.
| Feature | In FIPS mode | Alternative |
|---|---|---|
| Ed25519 and Ed448 keys (X.509 CAs and certificates, SSH CAs and SSH keys, deploy keys, OCSP responders) | Refused at creation and import. Existing Ed25519/Ed448 objects stay in the database but cannot be used: signing, CRL, OCSP, SCEP, renewal and SSH deployment answer a clear error, naming the CA or certificate where there is one | ECDSA P-256, P-384, P-521 or RSA. The SSH CA, SSH user keys and deploy keys default to ECDSA P-256 in FIPS mode (Ed25519 otherwise) |
| RSA below 2048 bits, curves other than P-256/P-384/P-521 | Refused | RSA 2048, 3072, 4096; NIST P-256, P-384, P-521 |
| SHA-1 signatures | The FIPS mode system policy allows SHA-256, SHA-384 and SHA-512 only; SCEP requests signed with SHA-1 are refused with badAlg (the FIPS reason is only in the log) |
SHA-256 or stronger. SHA-1 as a plain digest stays (OCSP CertID, SHA-1 fingerprint) |
| MD5 fingerprint | Not computed: the md5 field is null
|
SHA-256 (or SHA-1) fingerprint |
TSIG hmac-md5 (RFC 2136 DNS provider) |
Not offered; creating or switching a provider to it is refused, and an existing one sends nothing |
hmac-sha256 or another SHA-2 TSIG algorithm |
| PKCS#12 legacy export (3DES/SHA-1) | Refused | Default PKCS#12 export (AES-256), or PEM |
| JKS export | Refused | PKCS#12 (default mode), which Java reads as a keystore |
| PKCS#12 import | Refused: the module has no PKCS#12 key derivation, so no archive's MAC can be verified | Import the certificate as PEM and the private key as PEM or encrypted PKCS#8 |
| Argon2id backups | New backups use PBKDF2; requesting "kdf": "argon2id" is refused, and an Argon2id archive cannot be restored |
On the standard instance, create a backup with "kdf": "pbkdf2" (API, see Backup and Restore), and set Key derivation of scheduled backups to PBKDF2 |
| scrypt password hashes (from before v2.240) | Cannot be verified: the login fails and the password must be reset | Before switching, have each local user log in once on v2.240 or later: the hash is replaced with PBKDF2 at login |
| SCEP | 3DES content encryption and PKCS#1 v1.5 key transport are refused (badAlg); GetCACaps announces nothing refused, and replies never use PKCS#1 v1.5 |
Clients using RSA-OAEP and AES are served |
| NTLM to a Microsoft AD CS (WinRM admin channel) | Testing or saving an NTLM channel is refused; a stored NTLM channel is not opened | Kerberos transport (see Microsoft CA) |
| OpenBao / Vault Transit keys | Ed25519 and ChaCha20-Poly1305 Transit keys are not listed | RSA or ECDSA Transit keys |
| Issuance policy | An implicit FIPS mode system policy applies ahead of all others on every issuance path: RSA 2048 to 4096 and EC P-256 to P-521 keys, SHA-256 to SHA-512 signatures. It cannot be edited; your policies can only narrow it, and saving a policy that allows Ed25519 or Ed448 is refused | |
| Key generation and randomness | RSA and EC keys are generated by openssl genpkey on the module. The salts, IVs and nonces of backups and of the EST and SCEP envelopes come from the module's DRBG; the encryption of stored private keys and secrets (Fernet) takes its IV from the kernel |
- Upgrade the standard instance to v2.241 or later, on the standard image, and check that it runs normally.
-
Run the FIPS preflight, which lists what FIPS mode would refuse on this instance and changes nothing: Settings > About > Check FIPS readiness,
GET /api/v2/system/fips-preflight(permissionadmin:system), or from the command line:Each finding is a blocker, a warning or an information, with a remedy. The command exits with 0 when nothing blocks, 1 with blockers, 2 when a check could not run. On an instance already in FIPS mode, adddocker exec -u ucm -w /opt/ucm/backend ucm python -m scripts.fips_preflight # add --json for JSON
-e OPENSSL_CONF=/run/ucm/openssl-fips.cnftodocker exec: without it the command runs outside the module, reports afips.providererror and exits with 2. -
Replace what FIPS mode refuses: Ed25519/Ed448 CAs, SSH CAs and deploy keys (create ECDSA or RSA replacements and reissue), TSIG
hmac-md5DNS providers, NTLM admin channels to AD CS (switch to Kerberos), SCEP clients that only send 3DES or PKCS#1 v1.5, policies that allow Ed25519/Ed448. - Refresh password hashes: every local user logs in once (the scrypt hash is replaced at login). 2FA backup codes generated before v2.240 and EST, WSTEP and XCEP passwords set before v2.240 are not replaced at use: regenerate the codes and set the passwords again.
-
Back up with PBKDF2, so that the FIPS instance can restore the archive:
Set Key derivation of scheduled backups to PBKDF2 too. Keep a copy of both volumes as well (see Backup and Restore).
POST /api/v2/system/backup/create {"password": "...", "kdf": "pbkdf2"} -
Switch the image to
<version>-fipswith the same volumes, addUCM_FIPS=1(and the/run/ucmand/tmptmpfs if the root filesystem is read-only). -
Verify: the startup log line,
fips_active: trueon/api/v2/health, then issue a test certificate from each CA you use.
To go back, remove UCM_FIPS (the -fips image then runs in standard mode) or return to the standard image. Backups and password hashes written in FIPS mode use PBKDF2, which a standard instance reads.
- UCM is not validated. Only the OpenSSL FIPS Provider 3.1.2 holds a validation (CMVP #4985), and its certificate notes that it gives no assurance of the minimum strength of the keys it generates. Whether a deployment meets your requirements is your assessment.
- Operational environment. The tested configurations of certificate #4985 include Ubuntu 22.04 and Debian 11 on x86-64 (and FreeBSD, Windows and macOS platforms). The image is based on Debian 13, and the arm64 image runs on Linux aarch64: neither is in that list. The module runs there on platforms outside its tested configurations: what the CMVP calls user affirmation, which extends no validation to them. The library is the system OpenSSL 3.5 of Debian 13; the validated part is the provider it loads.
- Entropy. The module expects an entropy source supplied by its environment, outside the module boundary. The image relies on the host kernel's entropy, through OpenSSL; the 3.1.2 provider has no built-in jitter entropy source.
- SoftHSM is not a validated module. In FIPS mode no default SoftHSM token is created; a SoftHSM provider you configure still works, but its keys are not protected by a validated module.
- External HSMs carry their own validation: with an HSM-backed CA, signatures are made by the HSM, so check that HSM's certificate and mode (see HSM Support).
-
DEB and RPM packages run on the FIPS module of the distribution, whose validation is the distribution's: check its certificate and the configurations it covers for your release. Without
UCM_FIPS_BUILD=1, the packages install Python wheels that bundle their own OpenSSL, andUCM_FIPS=1refuses to start. Ubuntu 22.04 is not supported. -
PostgreSQL: in the
-fipsimage, psycopg2 is linked to the system libpq and OpenSSL. In FIPS mode, UCM refuses to start whenDATABASE_URLreaches PostgreSQL over TCP withoutsslmode=requireor stricter; useverify-fullwhen the server certificate can be checked. A server on the same host can be reached through its Unix socket instead, which needs no TLS:DATABASE_URL=postgresql://ucm:<password>@/ucm?host=/var/run/postgresql. See Database Backend.
In FIPS mode, UCM performs its cryptographic operations in a CMVP-validated module: the OpenSSL FIPS Provider 3.1.2 (certificate #4985) in the -fips image, or the FIPS module of the distribution with the DEB and RPM packages. Record the module's CMVP certificate in your register, with the systems that rely on it. UCM itself is not a validated cryptographic module and is not FIPS certified.
- NIST SP 800-53 Rev. 5 (FedRAMP), SC-13: a validated module is necessary but not sufficient. Authorization covers the whole system, including its environment, its operations and the provider's development controls.
- NIST SP 800-171 Rev. 2 (CMMC Level 2), 3.13.11: the requirement is FIPS-validated cryptography to protect CUI; FIPS mode helps meet it when the deployment is configured and operated as documented on this page.
- Outside the US and Canada, FIPS mode is supporting evidence at most (Australia's ISM, Germany's BSI TR-02102, France's ANSSI guide PG-083), and it does not cover national algorithm suites such as SM2/SM3/SM4 or GOST, which UCM does not implement today.
Whether a deployment meets a given framework depends on that framework and on how your organization supports it.
- Security: password hashing, key protection
- HSM Support: HSM-backed CA keys
- Backup and Restore: backup encryption and KDF
- Installation Guide: Docker volumes and environment
- Microsoft CA: WinRM admin channel transports
Getting started
Certificates and CAs
- CA Management
- CA Offline Mode
- Certificate Operations
- Certificate Templates
- Certificate Export
- Import and Export
- Import from OPNsense
- Certificate Toolbox
- Certificate Discovery
- Trust Store
- Approval Workflows
- Key Recovery
- Code Signing
- Deploy Hooks
- HSM Support
- SSH Certificate Authority
Protocols
- ACME
- SCEP
- EST
- OCSP Responder
- CRL and CDP
- AIA CA Issuers
- TSA (Timestamp Authority)
- Certificate Transparency
Integrations
Security and access
Operations
- System Configuration
- Database Backend
- Backup and Restore
- Monitoring
- Notifications
- Reports
- Dashboard
- Themes
- User Settings
Development
- Building from Source
- Contributing
- Developer Patterns
- Architecture
- API Reference
- API Documentation
- Roadmap
Releases