github NeySlim/ultimate-ca-manager v2.189

latest releases: v2.233-rc2, v2.233-rc1, v2.232...
2 months ago

What's Changed

Added

  • ACME LOT A — shared DNS self-check for proxy and renewal — the ACME proxy and auto-renewal paths no longer use a blind fixed 30s sleep after publishing the DNS-01 TXT record. Both now poll actively via services/acme/dns_selfcheck.py, honouring acme.client.dns_propagation_timeout (same setting as the ACME client auto-poll). If the TXT is still missing when the timeout elapses, the proxy skips upstream challenge submission and marks the challenge dns_not_ready instead of burning the token on the upstream CA. Renewal cleans up DNS TXT records on propagation or finalization failure.
  • ACME renewal partial TXT cleanup — multi-domain renewals now mark DNS TXT records for cleanup as soon as the first create_txt_record succeeds, so a failure on a later domain no longer leaves earlier TXT records behind.
  • GUI toggle: verbose ACME/DNS diagnosticsACME → Let's Encrypt → Verbose ACME/DNS logs (acme.client.debug_logging) promotes DNS resolver diagnostics (poll ticks, per-resolver failures, lookup source) from DEBUG to INFO for troubleshooting propagation issues without raising the global log level. The flag is memoized per app context, so hot poll loops do not query the database per log line. Default off.

Changed

  • ACME client DNS self-check refactor_dns_selfcheck / timeout reading in orders.py now delegate to the shared dns_selfcheck module used by proxy and renewal, keeping one implementation for poll interval, logging, and timeout semantics.

Fixed

  • AD CS Kerberos authentication crashed on a missing unused dependency — the kerberos auth mode built the certsrv client in NTLM mode before attaching the Kerberos handler, which made the certsrv library import requests_ntlm even though it was never used. Every Test Connection / sign in kerberos mode failed with "No module named 'requests_ntlm'". The client is now built with a neutral placeholder auth and the Kerberos handler attached directly; all three auth modes (basic, certificate/mTLS, kerberos) smoke-tested end-to-end against a Windows Server 2025 AD CS.

📜 Recent release history (last 2 versions)

[2.188] - 2026-07-08

Security

  • DNS provider credentials encrypted at rest (GHSA-38cv-3c4g-w55w) — DNS-01 provider API keys/tokens (Cloudflare, Route53, …) were stored as plaintext JSON in dns_providers.credentials despite the column being labelled encrypted, so anyone with database read access (or a raw export of the field) obtained domain-control credentials. The field is now encrypted at rest via a model property (utils.encryption Fernet, mirroring the EAB HMAC key), read paths transparently decrypt (legacy plaintext rows still read), and migration 052 encrypts any pre-existing rows. Backup export/restore round-trips the decrypted value so cross-machine restore keeps working; regression tested (round-trip, at-rest ciphertext, constructor/restore path, migration idempotency). Reported externally by Ralph.
  • Dev-dependency advisories — bumped transitive build/lint tooling out of vulnerable ranges via npm overrides: js-yaml → 4.3.0 (GHSA-h67p-54hq-rp68, quadratic-complexity DoS in merge-key handling; pulled in by eslint) and @babel/core → 7.29.7 (GHSA-4x5r-pxfx-6jf8, arbitrary file read via sourceMappingURL; pulled in by @vitejs/plugin-react). Both are build-time only and never shipped in the runtime bundle.

[2.187] - 2026-07-08

Added

  • Configurable public vhost for ACME directory URLs — a dedicated public hostname/port (acme_public_vhost, acme_public_port in Settings → General) can now be advertised in the local ACME server and ACME proxy directory URLs (/acme/*, /acme/proxy/*), independent of the admin UI URL — the split admin/ACME reverse-proxy topology (e.g. admin.ucm.example.com vs acme.ucm.example.com behind one wildcard certificate). JWS verification accepts both the advertised public origin and the inbound URL; without a configured vhost, behavior is unchanged (request host). Wildcard hostnames are rejected for the vhost value (TLS SAN concept, not an advertised URL), and an optional acme_public_tls_cert_id records which managed certificate to deploy on the ACME vhost (metadata only). Settings APIs expose acme_public_base_url / acme_proxy_public_base_url and the UI directory URLs follow the configured origin (#173, thanks @fredlubrano).

Changed

  • SQLAlchemy 2.0 Session.get — all 353 Model.query.get() / query.get_or_404() call sites migrated to db.session.get() / db.get_or_404(), eliminating ~4500 LegacyAPIWarning per test run ahead of a future SQLAlchemy major bump.

Security

  • CSR extension policy on certificate issuance — the shared CSR signer copied every requested extension into the issued certificate verbatim, so a crafted CSR carrying BasicConstraints CA:true (and keyCertSign) submitted through EST, SCEP or ACME enrollment could obtain a working subordinate CA — a trust escalation from an enrollment endpoint. Leaf certificate types now force BasicConstraints(ca=False) and strip the CA-only key-usage bits; only the explicit intermediate-CA signing flow may assert CA powers. Regression tested.
  • SCEP unauthenticated auto-enrollment when no challenge is set — per RFC 8894 §2.4 an omitted challengePassword allows unauthenticated authorisation, so with auto-approve enabled and no challenge configured any anonymous client on the public SCEP endpoint received a CA-signed certificate. Initial PKCSReq auto-issuance is now refused unless a challenge is configured (manual-approval mode and renewals are unaffected); UCM_SCEP_ALLOW_NO_CHALLENGE=1 opts back in for isolated deployments.
  • Key-strength floor on EST and SCEP enrollment — both protocols now reject CSRs whose public key is below policy (RSA < 2048, non-NIST EC curves) instead of signing weak/exotic keys, matching the UI/API issuance floor (EST RFC 7030 §3.7 and SCEP defer key policy to the local CA).
  • EST request-body cap bypass via chunked encoding — the body-size limit only inspected Content-Length, so a Transfer-Encoding: chunked request could stream an unbounded body into memory. The body is now read with a hard cap on the request stream regardless of framing.

Fixed

  • Broken settings restore endpointPOST /api/v2/settings/backup/restore passed a temp-file path where the service expects raw bytes, so it returned 500 on every call and left the uploaded (encrypted) backup in /tmp on each attempt. It now reads the upload as size-capped bytes in memory (no temp file) and restores correctly.
  • mTLS certificate import always failedPOST /api/v2/mtls/enroll-import crashed on every valid PEM (undefined variable, then a str stored into the binary cert_pem column). The endpoint now imports and enrolls correctly; covered by a regression test.
  • Public ACME vhost hardening (post-#173 review) — the local ACME server now accepts the JWS url on both the advertised public origin and the inbound request origin (the tolerance moved into verify_jws itself, shared with the proxy, so in-flight orders survive an acme_public_vhost change on /acme/* too); CAA enforcement and caaIdentities follow the configured public hostname instead of the inbound Host; the vhost is validated as a real FQDN (rejects .., leading/trailing hyphens, single labels); non-string vhost values and out-of-band garbage port rows return 400/defaults instead of 500; the public origin is memoized per request (one combined SystemConfig read instead of up to 10 per proxy request); the TLS certificate is picked from a dropdown of key-bearing certificates instead of a raw database id, and clearing it removes the config row; the CA Accounts panel shows the same public directory URLs as the other tabs.

Full history: CHANGELOG.md


Installation

Docker (Recommended)

# From Docker Hub
docker pull neyslim/ultimate-ca-manager:2.189

# Or from GitHub Container Registry
docker pull ghcr.io/neyslim/ultimate-ca-manager:2.189

# Run
docker run -d -p 8443:8443 \
  -e SECRET_KEY=$(openssl rand -hex 32) \
  --name ucm neyslim/ultimate-ca-manager:2.189

Debian/Ubuntu

wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.189/ucm_2.189_all.deb
sudo dpkg -i ucm_2.189_all.deb
sudo apt-get install -f

Fedora/RHEL

wget https://github.com/NeySlim/ultimate-ca-manager/releases/download/v2.189/ucm-2.189-1.fc43.noarch.rpm
sudo dnf install ./ucm-2.189-1.fc43.noarch.rpm

Silent/Automated Install

# Skip firewall prompts for CI/automation
sudo UCM_PORT=8443 UCM_FIREWALL=no dpkg -i ucm_2.189_all.deb

Default Credentials

  • Username: admin
  • Password: changeme123

Change the password immediately after first login!

Documentation

Don't miss a new ultimate-ca-manager release

NewReleases is sending notifications on new releases.