What's Changed
Security
- SSH: a requester could set any key ID, which sshd logs as the certificate holder's identity. Each SSH CA now names its certificates
principals@CA nameand refuses another key ID unless Let requesters set the key ID (allow_custom_key_id) is ticked (#432, reported by @danielrona). A principal can no longer contain a comma, which would read as two in that name.
Fixed
- ACME client: the ARI identifier of a certificate dropped the leading zero of a serial whose first bit is set (RFC 9773 §4.1), so renewal windows and
replaceswent wrong for such serials. It now follows the RFC, andreplacesis dropped on any refusal but a rate limit. - ACME client: a first name over 64 characters failed at finalization, once the challenges had passed. The name now goes in the SAN alone, marked critical.
- ACME client: a renewal waited a fixed 20 seconds for validation and finalization gave up after 30. Both now poll to the CA's configured timeout and honour
Retry-After. - ACME client: a renewal with
key_source=reusecertified again a key revoked as compromised, on its own certificate or an earlier one holding it. It now generates a new key, and an order with an external CSR holding such a key is refused. - ACME client: a threshold above two thirds of the certificate's life renewed it far too often. It now renews in the last third, and a renewal no longer asks for an email an existing account does not need.
- Backups: an HSM provider's PIN or token left in the archive under the source's database key, and read back empty on another installation. The archive now holds it in clear, under its password; a value only another key opens is dropped on restore, with a log entry asking to enter it again.
- HSM: generating a key under a name OpenBao or Azure Key Vault already held adopted that name, whatever the requested algorithm, and deleting it then destroyed the key of a live CA. The API now answers 409; bring an existing key in with a sync.
- HSM: two generations at once under one name could both find it free, and a key whose row could not be stored stayed in the HSM. Generations now take turns per provider (409 after 60 s), and such a key is removed unless a row holds its name.
- Database errors quoted bound values in logs and API messages, an unencrypted private key included. They are now hidden, except what PostgreSQL itself quotes in a DETAIL line: a duplicate key in full, or each column of a refused row up to 64 bytes.
- ACME client: every successful renewal left a second order on the schedule, so the orders doubled at each cycle. The renewed order now absorbs the one that fetched its certificate, and the upgrade removes the existing leftovers.
- ACME client: a failed renewal left the order it had opened behind, one row per attempt, and an order the CA had declared invalid still went to finalization, which hid the CA's reason. The order is now removed unless the CA may still complete it, and a scheduled renewal records the reason on the renewed order.
- ACME client: a status check replaced
issuedwith the CA'svalid, which took the order out of automatic renewal. An issued order now stays issued, and the upgrade puts back those still holding a valid certificate that no newer order replaced, proxy orders excepted. - ACME client: a finalization that failed on a database error, a refused import or a download the CA refused did not record the error on the order. It now does, without the SQL text and keeping a status the CA reported as valid, so the order can still be renewed.
- HSM: a CA whose creation failed after its key was generated left that key in the HSM and in the key list. It is now removed, where the provider allows it.
- HSM:
extractablesent as text, such as"false", generated an exportable key. The API now answers 400. - XCEP: a CA with no template to announce sent empty policy and OID collections, which Windows clients refuse with
WS_E_INVALID_FORMAT. Both are now nil, and the client sees a policy server with no templates. - Templates: a switch sent as text, such as
"autoenroll_enabled": "false", was stored as on, and a badis_activefailed a whole import. The API now answers 400, and an import skips only that template, with the reason. - Restore: text in a boolean column, such as
"is_active": "false", turned the setting on. The archive is now refused. - ACME profiles: renaming a profile bound to a disabled template was refused as a new binding. A rename now keeps the binding, and a second profile on that template is still refused.
- Public endpoints: with the HTTP protocol port set to 0 and a Protocol Base URL without a port, CRL, OCSP and AIA URLs were issued as
http://host:0/.... They now use port 80, the preflight check probes it, and the upgrade corrects the URLs stored on each CA (discussion #433, reported by @avdpas, thanks @Hemsby). - Google Cloud KMS: the notice for ML-DSA keys now says that KMS signs at most 64 KiB, which rules out a larger CRL.
Changed
- Certificates:
serial_numberandcarefare indexed, so renewal, revocation and protocol lookups no longer scan the table (migration 120).
Upgrade notes
- ACME client: the upgrade removes each order a past renewal left behind, recognised by holding the certificate and order URL of an older order. It also puts orders back on the renewal schedule if a status check had taken them off, so a certificate you had stopped relying on can renew: delete its order if you do not want that.
- ACME client: two orders for the same names that have already renewed apart cannot be told from two wanted orders, so both keep renewing: delete the one you do not want.
- Templates: the API and import accept only true or false for
is_active,enforce_san_types,ad_derived_subjectandautoenroll_enabled; 0 and 1 are refused. - Public endpoints: certificates issued before this update keep a
:0in their CRL, OCSP and AIA URLs: reissue them. - SSH: the option is off for every CA, existing ones included. A client that sends
key_idgets a 400 until the option is ticked on its CA; sending the CA's ownprincipals@CA nameis still accepted.
📜 Recent release history (last 2 versions)
[2.248] - 2026-11-01
Added
-
Keys: ML-DSA-44, ML-DSA-65 and ML-DSA-87 (FIPS 204) are recognised by policies, CSR parsing and key labels when the linked OpenSSL provides them (3.5 or later). They are refused in FIPS mode.
-
ML-DSA keys can be generated for CAs, certificates, CSRs and templates, and a renewed ML-DSA key keeps its level. Their certificates carry signature-only key usage (RFC 9881): a bit a template or CSR asked for is removed with a notice, and a digest asked for an ML-DSA signer is ignored with a notice.
-
ML-DSA authorities sign their CRLs and OCSP responses without a digest, under the OID of their own level, and OpenSSL 3.5 verifies them, delegated responders across RSA and ML-DSA included.
-
Policies, compliance profiles and both preflights recognise an ML-DSA signer as the
ml_dsascheme, soallowed_signature_schemesandpq_standaloneapply to what an ML-DSA authority signs. An ML-DSA key scores like the classical curve of its NIST category. -
Post-quantum certificates, CAs and CSRs (ML-DSA, SLH-DSA) are shown under their own name with their security level and a Post-quantum badge, in the API, the trust store, the mTLS list and compliance grading. A key the API does not name is no longer displayed as RSA.
-
Certificate chains, issuer lookups, smart import and delegated OCSP responders verify ML-DSA signatures. An unverifiable self-issued certificate whose key identifiers point at another key is no longer taken for a root.
-
ML-DSA private keys written by OpenSSL in its default seed-and-expanded layout import, read from their seed after a consistency check. A key without its seed, or one whose two halves disagree, is refused with a message that says what to do.
-
PKCS#12, PFX and JKS exports of an ML-DSA key answer 400 with the reason
unsupported_for_key_algorithminstead of a 500, and the export dialog greys these formats out. P7B bundles are built in-process instead of by the openssl command. -
The Create CA, Issue Certificate, Generate CSR and template forms offer ML-DSA-44, ML-DSA-65 and ML-DSA-87, and Create CA hides the signature hash when the key that signs takes none. These keys are not offered in FIPS mode or on an HSM.
-
Hybrid certificate pairs (RFC 9763): the Issue Certificate form and
POST /api/v2/certificateswithhybrid: {classical, pq}issue a classical certificate and an ML-DSA one whose relatedCertificate extension names it. The pair is shown linked, revokes together and renews together when the server holds both keys, unless the operator unticks the box, and exports as onehybrid-bundleZIP. -
A CSR carrying a relatedCertRequest (RFC 9763) signed by the key of a certificate held here is checked before signing on Sign CSR, ACME, EST and WSTEP, and the new certificate is linked to it;
POST /api/v2/csrsbuilds one withrelated_to, which needsread:private_keysand is audited. A request is bound to the first key it is presented with, and A's chain is checked as RFC 5280 asks. A newer certificate naming the same A takes over the pair, and ACME revocation revokes only the certificate presented. Such a pair satisfies thepq_standalonerule of compliance profiles. -
ACME: the local server finalizes ML-DSA CSRs, and the ACME client orders ML-DSA-44, ML-DSA-65 and ML-DSA-87 certificate keys outside FIPS mode. A default key type the client cannot generate now fails the order instead of falling back to RSA-2048.
-
EST, SCEP and WSTEP enrol ML-DSA keys: SCEP verifies ML-DSA CMS signers as RFC 9882 sets out, and XCEP announces ML-DSA templates in policy schema 3 with the software KSP and a SHA-512 request hash, which Windows Server 2025 follows to enrol them. EST /serverkeygen still generates RSA-2048 and ignores the request key, ML-DSA included (RFC 7030).
-
TSA: a timestamp signer can be ML-DSA-65 or ML-DSA-87 (RFC 9882), issued from the TSA page or as an ML-DSA CA signing directly.
-
HSM: ML-DSA-44, ML-DSA-65 and ML-DSA-87 keys can be generated on PKCS#11 3.2 tokens, OpenBao Transit and Google Cloud KMS, and a CA on such a key signs certificates, CRLs and OCSP responses. Google Cloud KMS support follows the KMS API but is not yet tested against the service, and the forms say so; Azure Key Vault and AWS CloudHSM refuse ML-DSA with the reason.
-
Compliance profiles: ANSSI, BSI and EU ACM accept ML-DSA-65 and ML-DSA-87 as the post-quantum member of a hybrid pair, never alone.
-
The effective policy endpoint reports
ml_dsa, and key type forms, the ACME client's included, offer ML-DSA only on a build that has it and outside FIPS mode. The FIPS preflight reports ML-DSA CAs under a newca.unapproved_algorithmcheck and lists ACME client orders whose CSR key FIPS does not approve. -
The "Certificates Only" API key scope now covers SSH certificates (
read:ssh,write:ssh) and reads SSH CAs (thanks @danielrona). -
CAs: "Hide from issuance" in the CA details keeps a CA, a root typically, out of the CA lists of Issue Certificate, Sign CSR, bulk CSR signing, user mTLS certificates and the TSA signing certificate; a link under those lists shows it again (#430).
-
Templates: a template, a system one included, can be deactivated from its details; the Issue Certificate form and Windows autoenrollment no longer offer it, and a CA left with no active template, its pinned ones all deactivated included, offers none. A system template still cannot be edited: duplicate it to change it.
Changed
-
CRL settings: the CRL digest of an Ed25519, Ed448 or ML-DSA authority is reported as empty and setting one answers 400; the CRL page only offers to clear one saved before.
-
Issuance: an unknown
keyAlgoonPOST /api/v2/cas, or an unknown key type on a certificate, CSR or template, now answers 400 instead of falling back to RSA-2048. SLH-DSA CSRs are refused as not signable by this instance. -
SSH CA routes now require the new
read:ssh_cas,write:ssh_casanddelete:ssh_casscopes, sowrite:sshno longer creates or edits SSH CAs. Upgrade note: roles, groups and API keys holding an SSH scope receive the matchingssh_casscope on upgrade and when an older backup is restored. -
FIPS mode: the ACME client, EST, SCEP and WSTEP refuse a CSR key FIPS does not approve (RSA under 2048 bits, Brainpool, EdDSA, ML-DSA, SLH-DSA) with a message that names FIPS, before checking the CSR signature.
Fixed
-
OCSP: a CA whose certificate carries a compressed EC point is found by its issuerKeyHash instead of answering unauthorized, and the responder ID hashes the key as the certificate encodes it. A multi-certificate request signed by an ML-DSA responder no longer fails.
-
CSRs: re-keying or cloning a CSR turned an EC P-384 or ML-DSA request into RSA-2048 or P-256; the request now keeps its key type.
-
ACME accounts: the account detail named every key RSA-2048; the list and detail now return the key the account's JWK holds.
-
Generated CSRs: an Ed25519 or Ed448 key was signed with the requested SHA-2 digest and failed; keys whose scheme takes no digest are now signed without one.
-
CA details and renewal with a new key: an algorithm without a size or curve no longer falls back to the first algorithm of its family.
-
Smart import: an encrypted private key was kept in its encrypted form and silently dropped on import; the decrypted key is now matched and stored. A wrong key password now stops the import with its reason instead of importing the certificate alone, and a key given with a password it does not need is read.
-
Key uploads, the key matcher and the converter: a malformed key now answers 400 with its reason instead of a generic error, or of a 200 that returned the certificate alone.
-
Generate CSR now offers RSA-3072, and re-keying an RSA-3072 request keeps that size. Create CA's "Use existing key" lists only the HSM keys the policies, the compliance profile and FIPS mode allow.
-
ACME client settings now flag a saved certificate key type this server no longer offers, instead of showing an empty field.
-
Template preview: an RSA-2048 template was shown as "RSA-2048 256-bit"; it now shows the key's name.
-
ACME DNS-01 with GoDaddy: TXT records were written with a PATCH the API does not offer, and removed with an empty PUT it refuses. The values of a name are now read, merged and written back with PUT, and cleanup uses DELETE.
-
ACME DNS-01 with deSEC: a new TXT record used a 300 s TTL, below the 3600 s minimum deSEC sets on each domain, and was refused. The domain's minimum TTL is now applied, and apex records are cleaned up.
-
ACME DNS-01: the ACME client, renewals and every cleanup now take the per-name lock the proxy uses, so two writers of one
_acme-challengename no longer drop each other's value. -
ACME DNS-01 with PowerDNS: a value already present but disabled was added a second time, which PowerDNS refuses; it is now re-enabled. With Route 53, an alias or routing-policy TXT record is no longer overwritten or deleted, and the existing set is found whatever the case of the name.
-
CAs: when the hourly check merged two records of one CA, the SCEP, EST, XCEP, WSTEP, TSA, mTLS and ACME settings that named the removed record kept pointing at it. They now follow the kept record, with the SCEP challenge and the CRL and OCSP publication flags, and the removed record's URLs resolve to it; EST labels also follow a duplicate converted into a cross-certificate.
-
SCEP: an EC or other non-RSA CA was accepted as the default CA and on a profile, although SCEP clients encrypt their request to an RSA key, so every enrolment failed. It is now refused and left out of the pickers; one already saved is reported as not usable on the dashboard, and the SCEP endpoint says why.
-
Settings: the mTLS trusted CA picker hid CAs without a key, although the trusted CA is the anchor of client certificates; it now lists every CA whose certificate is not revoked, keyless or offline included, and keeps the saved one. The ACME domain form no longer puts a space between two Japanese or Chinese sentences.
-
API: an HTTP error without a dedicated handler, such as the login attempt limit or a request whose body is not JSON, answered 500 with a stack trace in the log; it now keeps its own status (429, 415...) and headers. A POST to
/api/v2/auth/methodsanswers like the GET, whatever its body. -
Behind a reverse proxy that sent
Connection: upgradeon every request, a request with a body, such as the login, hung until the proxy timed out: the server took it for a WebSocket handshake. Only a request withUpgrade: websocketis now treated as one. -
ACME server: revoking a certificate with its own key, when that key cannot sign a request (EdDSA, Brainpool, ML-DSA), answered a bare 403; the answer now says to revoke with the ordering account.
-
Certificates issued through ACME, SCEP, EST, WSTEP and Microsoft CA connections, or renewed, were stored without their key identifiers, or in lower case, so ACME renewalInfo answered 404 and the issuing CA was not found by them; they are now recorded with the certificate.
-
Import: a certificate or CA with an encrypted private key and a wrong or missing password, or with a key that could not be read, was imported without its key; the import now answers 400 with the reason. Key uploads say whether a password is missing or wrong, and smart import tries every per-file password the form sends instead of ignoring them. Smart import also ignored the objects left unselected and the Import keys option, and now offers Import CSRs.
-
WSTEP: renewing a certificate from Windows (
certreq ... Renew) was refused for lack of a WS-Security header; Windows authenticates with the certificate being renewed as TLS client certificate, which is now accepted when it signed the request, is current and was issued by the WSTEP CA. It needs mTLS enabled with that CA, or one of its ancestors, trusted. -
WSTEP: a renewal could move to another template and add its Extended Key Usages; it now keeps the template of the certificate it renews with that template's EKUs, and a renewal wrapped in PKCS#7 with a new key has to prove possession of it.
-
EST, SCEP and WSTEP: two renewals of one certificate sent at the same time, or two pending SCEP renewals approved in turn, could both be issued; the second is now refused as superseded, and a SCEP renewal approved after the certificate was revoked is refused. WSTEP renewals of a certificate the CA issued, refused ones included, are audited with the old and new serial numbers.
-
WSTEP: a request matched to a template by its EKUs could be issued with a key of another kind than the template's; it is now refused with the template's key type.
-
HSM: AWS CloudHSM providers accepted Brainpool keys the module cannot generate and failed with a 500; they now answer 400 with the reason. OpenBao no longer signs with a key type it cannot name, and a Google Cloud KMS key version without a digest is refused instead of signed with SHA-256.
-
CSRs: re-keying a Brainpool or ML-DSA CSR in FIPS mode sent a key type the server refuses; the form now falls back to the first key type it offers.
-
Certificates: a direct
/certificates/{id}link closed its detail window at once when "Close on navigate" was on. -
Certificates: the row actions of the certificate list (export, rename, renew, revoke, delete) had disappeared, which left renaming unreachable; they are back with the detail view's permissions and revocation dialog, and renaming is also offered in the detail views.
-
WebSocket: SSH certificate events reached every holder of
read:certificates; they now reach holders ofread:sshonly.
Security
-
dnspython 2.9.1 (CVE-2026-114605): a DNS message with a long chain of compression pointers, sent to the RFC 2136 listener or returned by a resolver, could hold a CPU. The listener reads compressed names the same way under the new version.
-
ACME server:
revoke-certsigned with a certificate's own key found the stored certificate by serial only, so a self-signed certificate forged with the serial of an issued one revoked it. Revocation now acts only on the stored certificate, byte for byte. -
Smart import and the format converter: an encrypted key or PKCS#12 file, including a key sealed in an inner encrypted layer, could ask for any number of key-derivation iterations. Costs above 2 million PBKDF2 or PKCS#12 MAC iterations, or scrypt above N=2^20, are now refused without being run, and a request makes at most 64 password attempts. Certificate and CA import, key uploads, the decoder, the key matcher and offline CA restore apply the same limits.
[2.247] - 2026-10-30
Added
-
HSM: a connection test records what a PKCS#11 module reports (library, manufacturer, library and firmware versions), shown on the provider's page. In FIPS mode a new SoftHSM provider is refused, since SoftHSM is not a validated module;
UCM_FIPS_ALLOW_SOFTHSM=1allows one for tests. -
Users: an administrator lists another user's API keys in their details and revokes a leaked or unused one, which stops working at once; a revoked or expired key can then be deleted. Each action is audited.
-
CAs: a CA can carry cross-certificates (same subject and key, another issuer) beside its own certificate: attach one, serve it in the default chain, export it, or cross-sign a held CA's key with another from the CA details; revoking one at its issuer is done through the API. Its expiry raises the usual alerts and its revocation follows the approval policies (#400).
-
Chains: exports, deployments, TLS, PKCS#12, ACME, WSTEP and TSA use one chain builder that follows the served cross-certificate;
chain_variant(auto,primary,cross:<id>) picks another chain on CA and certificate exports and on a deploy binding, and EST/cacertsadds the served cross-certificates (#400). -
ACME: the server offers the other chains of an order as RFC 8555 §7.4.2 alternates for
certbot --preferred-chain. AIA serves/ca/{ref}.p7cand/ca/{ref}/cross/{id}.cer, and.cerand.pemfollow the served cross-certificate (#400). -
Import: a certificate that re-certifies a held CA's key is attached as a cross-certificate on a self-signed root, and on an intermediate after the Attach as cross certificate choice (
cross_mode). Smart Import attaches one next to a held root and reportscross_certificate_attached(#400). -
CAs: a CA's details list the certificates and deploy bindings that still chain to it, directly or through a cross-certificate, to show when an old root can be retired;
GET /api/v2/cas/{id}/chain-usage(#400). -
CAs: the chain repair bar lists records damaged before cross-certificates were modelled, with Convert to cross-certificate and Restore as primary; nothing is changed without a click (#400).
Fixed
- Import: a CA certificate re-issued by another CA over the same key overwrote the self-signed root and re-parented it. An intermediate in that case now answers 409
cross_certificate_detected, and so does installing it after Renew via CSR, with Attach as cross certificate and Replace offered; a root rollover under the same issuer name still replaces the certificate (#400). - Smart Import: a cross-certificate in a bundle replaced the self-signed root or was dropped under a generic duplicate warning depending on file order. The root is kept and the result reports
cross_certificate_attachedorcross_certificate_skipped(#400). - CAs: the hourly chain repair deleted a self-signed root when a second record shared its key. It now merges only identical certificates and reports the rest (#400).
- ACME client:
preferred_chainmatched the subject or issuer of the last certificate and preferred an alternate, so a cross-certificate could win a request for the other root. It now follows certbot: the issuer CN of the topmost certificate, default chain first (#400). - OCSP, mTLS and renewal resolved a CA through whichever record shared its key, so a cross-certificate could stand in for the self-signed root. They now prefer the self-signed record (#400).
- DEB and RPM: an upgrade stopped UCM while it rebuilt the Python environment, about five minutes with
UCM_FIPS_BUILD=1. The new environment is now built next to the running one, and the service stops only to switch to it. - UI: 17 badges asked for a size that does not exist and rendered without padding, and a few for a colour that does not exist (About, SSO tests, Smart Import, failed webhook deliveries, ACME order status). They now use defined ones, and a test refuses an unknown size or colour.
- UI: a stat card clicked to filter a list (Certificates, SSH and user certificates, Policies, Discovery, Approvals) showed no active state on desktop, so nothing said which filters were on. Active cards are outlined again.
- CSRs: the Pending and History tabs showed at most 20 requests and every count stopped at 20; both lists now page, search and sort on the server, and History also searches by signing CA (#424, thanks @clinde04).
- ACME client: an order for a domain and its wildcard kept only one of its two authorizations, which both name the base domain, so it never completed. Each now gets its own TXT value and challenge.
- ACME DNS-01: the Route 53, Azure, Gandi, deSEC, PowerDNS and NS1 providers replaced the TXT record with the new value, or refused it, so a domain and its wildcard could not both validate; they now add it to the existing values (Route 53 now needs
route53:ListResourceRecordSets, which cleanup already used). DuckDNS, Hurricane Electric and the FreeDNS provider still keep one TXT value per name. - ACME DNS-01: the Hetzner provider added a TXT value to an existing record with a PATCH the Hetzner Cloud API does not offer, so a domain with its wildcard, or a retry after a leftover value, failed. It now uses
add_recordsand keeps the record's TTL. - CAs: a root imported without its private key showed as active but was silently left out of every CA picker. It is now marked No private key with an Import private key action, and the pickers (issuing, signing, cross-signing, ACME, SCEP, EST, TSA, Windows enrollment, mTLS enrollment) say how many CAs they leave out; the API refuses a CA that cannot sign as SCEP default (an HSM-backed one too, which SCEP cannot use) or EST label, the default SCEP CA can be cleared and can no longer be deleted while set, and a policy can target any CA again (#426).
Full history: CHANGELOG.md
Installation
Docker (Recommended)
# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.249
# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.249
# Run
docker run -d -p 8443:8443 \
-e SECRET_KEY=$(openssl rand -hex 32) \
--name ucm neyslim/ultimate-ca-manager:2.249Debian/Ubuntu
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.249/ucm_2.249_all.deb
sudo dpkg -i ucm_2.249_all.deb
sudo apt-get install -fFedora
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.249/ucm-2.249-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.249-1.fc43.noarch.rpmRHEL, AlmaLinux, Rocky Linux 9
wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.249/ucm-el9-2.249-1.el9.noarch.rpm
sudo dnf install ./ucm-el9-2.249-1.el9.noarch.rpmFIPS mode (preview)
FIPS mode is a preview: feedback is welcome on #399. Full guide: FIPS Mode.
Docker, any Linux host (amd64, arm64):
docker run -d -p 8443:8443 -e UCM_FIPS=1 \
-v ucm-data:/opt/ucm/data -v ucm-config:/etc/ucm \
--name ucm neyslim/ultimate-ca-manager:2.249-fipsUbuntu 24.04 with Ubuntu Pro (sudo pro enable fips-updates, then reboot):
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_2.249_all.debRHEL, AlmaLinux, Rocky Linux 9 (sudo fips-mode-setup --enable, then reboot; on RHEL, enable CodeReady Builder instead of CRB):
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-2.249-1.el9.noarch.rpmThe package builds its crypto libraries against the system OpenSSL (about five minutes), sets UCM_FIPS=1 on a host in FIPS mode and prints a readiness report. Fedora, Debian and other distributions are not supported in FIPS mode: use the Docker image.
Silent/Automated Install
# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.249_all.debDefault Credentials
- Username:
admin - Password:
changeme123
Change the password immediately after first login!
Documentation
- Installation Guide
- API Documentation