chore(version): bump to 1.9.0 - CSR creation

- backend/version.json + frontend package version to 1.9.0
- README: feature list entry, CSR workflow section, SSL CSR API reference,
  v1.9.0 release notes
- UPGRADE_GUIDE: v1.9.0 section (additive ssl_csrs table, SCHEMA_VERSION
  9 -> 10, no RBAC changes, zero agent impact, rollback note)
This commit is contained in:
mustafa.ulukaya
2026-08-04 21:24:34 +03:00
parent af07d72514
commit 69e12f7459
5 changed files with 77 additions and 6 deletions
+47
View File
@@ -105,6 +105,7 @@ This architecture provides better security (no inbound connections to HAProxy se
**Version Control & Rollback** - Every change versioned with one-click restore capability
**Real-Time Monitoring** - Live stats, health checks, and performance dashboards
**SSL Certificate Management** - Centralized SSL with expiration tracking
**CSR Creation** *(v1.9.0)* - Generate a private key + CSR in-app (RSA 2048/4096, ECDSA P-256/P-384, full subject + SANs), have it signed by any external CA, then import the signed certificate — the key never leaves the server
**ACME Auto SSL (Let's Encrypt)** - Automated certificate issuance, renewal, and deployment via ACME protocol
**ACME DNS-01 Challenge** *(v1.8.0)* - TXT-record validation for internal/isolated clusters (no public port 80) and wildcard certificates; pluggable DNS providers (Manual + Cloudflare), opt-in, HTTP-01 unchanged
**ACME Certificate Diagnostic Panel** - Automated preflight that checks agent readiness, DNS resolution, port 80 reachability, and ACME challenge ACL before issuing certificates
@@ -778,6 +779,15 @@ User Updates SSL in UI → All Agents Poll Backend (30s)
→ Validate Config → Reload HAProxy (zero downtime)
```
#### CSR Workflow (external / corporate CAs) — v1.9.0
For certificates signed by an external or corporate CA, the **CSR tab** on the SSL Certificates page covers the whole flow without the private key ever leaving the server:
1. **Create CSR**: pick a name (becomes the certificate name / on-agent file path), Common Name, optional SANs and subject fields (O/OU/L/ST/C/email), and a key algorithm (RSA 2048/4096 or ECDSA P-256/P-384). The backend generates the key + CSR; only the CSR PEM is shown (copy or download as `.csr`).
2. **Get it signed**: submit the CSR to your Certificate Authority.
3. **Import**: paste the signed certificate (+ optional chain), choose Global or cluster-specific scope and usage type. The backend verifies the certificate matches the stored key, rejects expired certs, warns on SAN drift, and creates a normal SSL certificate entry (source: `CSR`).
4. **Deploy**: the imported certificate goes through the standard **PENDING → Apply Management → agent pull** pipeline like any other certificate.
#### Key Features
- **Certificate Upload**: PEM format certificate and private key upload
- **ACME Automation**: Automatic certificate issuance and renewal via Let's Encrypt / ACME protocol (see [ACME Auto SSL](#acme-auto-ssl---automated-certificate-management))
@@ -1856,6 +1866,42 @@ GET /api/backends?cluster_id=1
GET /api/frontends?cluster_id=1
```
### SSL CSR API (v1.9.0)
```bash
# Create a CSR (generates the private key server-side; response contains the
# CSR PEM — the private key is never returned by any endpoint)
POST /api/ssl/csrs
Authorization: Bearer <token>
{
"name": "www-example-com",
"common_name": "www.example.com",
"sans": ["api.example.com"],
"key_algorithm": "rsa-2048", # rsa-2048 | rsa-4096 | ecdsa-p256 | ecdsa-p384
"organization": "Example Corp",
"country": "TR"
}
# List CSRs (metadata only, no PEM)
GET /api/ssl/csrs
# CSR detail (includes the CSR PEM)
GET /api/ssl/csrs/{csr_id}
# Import the CA-signed certificate for a pending CSR
POST /api/ssl/csrs/{csr_id}/import
{
"certificate_content": "-----BEGIN CERTIFICATE-----...",
"chain_content": "-----BEGIN CERTIFICATE-----...", # optional
"usage_type": "frontend", # frontend | server
"is_global": false,
"cluster_ids": [1, 2]
}
# Delete a CSR (pending: permanently destroys the private key;
# completed: removes history only — the imported certificate is unaffected)
DELETE /api/ssl/csrs/{csr_id}
```
### ACME / Let's Encrypt API
```bash
# List ACME accounts
@@ -2428,6 +2474,7 @@ Developed with ❤️ for the HAProxy community
## Release Notes
- **v1.9.0** (2026-08-04) — **CSR creation** (in-app key + CSR generation and signed-certificate import): a new **CSR tab** on the SSL Certificates page generates a private key and Certificate Signing Request server-side (RSA 2048/4096 or ECDSA P-256/P-384; full subject — O/OU/L/ST/C/email — plus DNS SANs with wildcard support), for certificates signed by an **external or corporate CA**. The operator downloads/copies the CSR PEM, has it signed, then imports the signed certificate (+ optional chain): the backend verifies the certificate against the stored key (hard gate), rejects expired certs, warns on SAN drift, and creates a normal SSL certificate entry (source `CSR`) that flows through the standard **PENDING → Apply Management → agent pull** pipeline. The private key **never leaves the server** — no CSR endpoint returns it, and after import the CSR row's key copy is destroyed (the key then lives only on the certificate, like every other key). Additive schema change: one new table `ssl_csrs` (SCHEMA_VERSION 9 → 10, auto-migrated, no existing table altered); key generation runs off the event loop and is rate-limited per user; existing `ssl.*` permissions govern all new endpoints. No agent or rendered-config changes.
- **v1.8.7** (2026-07-09) — **Version reporting single-source fix**: the version shown in the UI (backend-sourced via `/api/version`) could lag behind the real release. The canonical version lived in the repo-root `version.json`, but the backend image is built from the `./backend` context, so that file did not reach the container in every pipeline; the backend then fell back to a hardcoded constant in `main.py` that had to be bumped by hand and had drifted (it reported 1.8.4 after 1.8.5/1.8.6 shipped). The version now lives in a single file, `backend/version.json`, baked into every image automatically, and `main.py` no longer carries a real version literal (its fallback is a neutral "unknown"). A new test enforces that the version stays single-source and cannot drift. No functional or API change.
- **v1.8.6** (2026-07-06) — **Performance: opt-in API workers + heartbeat micro-optimization** (Issue #35 follow-up): the backend container can now run multiple uvicorn worker processes via the new `UVICORN_WORKERS` environment variable (default **1** — behavior unchanged unless you opt in), letting the API use all cores on multi-core hosts; background tasks were already multi-replica safe, as exercised by the Kubernetes HPA deployment. The agent heartbeat handler now reads the agent's `status`/`version`/`upgrade_status` in one query instead of three (one round-trip per heartbeat, per agent, every 30s). Added a *Performance Tuning* section to the README (worker/replica scaling and how to use the `X-Response-Time` header and `Slow request detected` logs to pinpoint slow endpoints). Zero-risk release: no schema, API, or agent changes; defaults preserve existing behavior exactly.
- **v1.8.5** (2026-07-03) — **ACME completion-task SQL fix** (Issue #35 follow-up): the background order-completion task (`complete_pending_acme_orders`, runs every 60s) died on **every cycle** with `syntax error at or near ")"` — an extra closing parenthesis introduced in v1.8.0's bounded DNS-01 retry claim query. Because that query is the task's first database call, **no background ACME work ran at all from v1.8.0 through v1.8.4**: orders were never claimed for finalize/download, the DNS-01 TXT record was never published (so DNS-01 with an automated provider such as Cloudflare could never validate), Site Wizard staged orders never left `wizard_staged`, and DNS-01 retry/TXT-cleanup never executed. The stray parenthesis is removed and a regression test now scans all ACME modules' SQL for unbalanced parentheses (the unit suite mocks the database, which is why a raw-SQL syntax error could slip through). One-line backend query fix; no schema, API, or agent changes — fully backward compatible.
+24
View File
@@ -1,3 +1,27 @@
# Upgrade Notes — v1.9.0 (CSR creation)
**Backward compatible & additive.** Upgrading to v1.9.0 changes nothing for existing
clusters/agents until you create a CSR:
- **Schema:** `SCHEMA_VERSION` bumps to `10`, so on first start the (idempotent)
migration sequence re-runs once and adds **one new table** (`ssl_csrs`) plus its
indexes. **No existing table is altered**, existing rows are untouched, and the
**admin password is not reset**. No new permission strings are introduced — all CSR
endpoints are governed by the existing `ssl.create` / `ssl.read` / `ssl.delete`
permissions, so custom roles need no changes.
- **Key storage:** CSR private keys are stored in the database like every other key
in the system (`ssl_certificates.private_key_content` and the ACME order keys).
The key is never returned by any CSR API endpoint, and after a successful import
the CSR row's key copy is set to NULL (the key then lives only on the certificate
row).
- **Agents:** zero agent changes. Agents never read the new table; a CSR becomes
visible to agents only after its signed certificate is imported **and** applied via
Apply Management (the standard PENDING pipeline).
- **Rollback:** simply don't use the CSR tab. The `ssl_csrs` table is inert when
empty; downgrading the application leaves it as an ignored extra table.
---
# Upgrade Notes — v1.7.0 (HA / VIP Keepalived management, Issue #27)
**Backward compatible & opt-in.** Upgrading to v1.7.0 changes nothing for existing
+3 -3
View File
@@ -1,5 +1,5 @@
{
"version": "1.8.10",
"releaseName": "Security hardening — RCE, missing-auth and SSRF advisories (GHSA-7rhv/3p5c/3vh4)",
"releaseDate": "2026-07-20"
"version": "1.9.0",
"releaseName": "CSR creation — in-app key+CSR generation and signed-certificate import",
"releaseDate": "2026-08-04"
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "haproxy-openmanager-frontend",
"version": "1.8.10",
"version": "1.9.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "haproxy-openmanager-frontend",
"version": "1.8.10",
"version": "1.9.0",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@ant-design/icons": "^5.0.0",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "haproxy-openmanager-frontend",
"version": "1.8.10",
"version": "1.9.0",
"description": "HAProxy Load Balancer Management UI",
"license": "AGPL-3.0-or-later",
"dependencies": {