2 Commits

Author SHA1 Message Date
mkellermann97
4844bf4c9b hotfix: v0.9.10.3 — fresh-install failure on the multi-tier keystore (#417)
Reported by @tgmct: every fresh v0.9.10 install where deploy.sh runs Step 5
(master-key bootstrap) results in pegaprox.service failing to start with
`PermissionError: [Errno 13] Permission denied: '/etc/pegaprox/secret.key'`.

Root cause: deploy.sh Step 5 wrote /etc/pegaprox/secret.key with mode
0600 root:pegaprox. The systemd unit runs as the `pegaprox` service user.
Owner is root, group is pegaprox, but mode 0600 grants read only to the
*owner* — the service user (a group member, not the owner) cannot read
its own master key. So every fresh install boot-loops.

Three-part fix:

(1) deploy.sh Step 5: master key now created at 0640 root:$SERVICE_GROUP
    (group-readable so the service can load it). Key directory is now
    0750 to match.

(2) deploy.sh Step 5: existing v0.9.10 / v0.9.10.1 / v0.9.10.2 installs
    self-heal on the next `update.sh` — if /etc/pegaprox/secret.key is
    found at mode 0600 or 0400, deploy.sh bumps it to 0640 and logs a
    `(#417 repair)` print_info. A key already at 0640 / 0440 is left
    untouched.

(3) pegaprox/core/keystore.py `_enforce_perms` was relaxed from "must be
    0600" to "must be 0600 OR 0640". Anything with group-write,
    group-exec, or any other-perm bit set is still rejected hard — the
    function raises RuntimeError, not silent skip, so an accidentally
    world-readable key never becomes the active key.

Hard rejection mask is now exactly `S_IWGRP | S_IXGRP | S_IRWXO`.
Accepted modes: 0600, 0400, 0640, 0440. Verified with 8-case unit pass.

docs/SECURITY.md tier table updated: Tier 4 row now states "chmod 0640
root:pegaprox — group-read required" and explains why 0600 root:pegaprox
is unreadable for the service. The "loose-perms" paragraph corrected
from "skipped" to "rejected" (matches the actual code behaviour).

Workaround for existing installs that hit the bug *before* this update
can be applied (i.e. operators stuck at boot-loop on v0.9.10/.1/.2):

  sudo chmod 640 /etc/pegaprox/secret.key
  sudo systemctl restart pegaprox

Files touched:
- deploy.sh (Step 5: 3x chmod 600 -> 640, dir 700 -> 750, repair-on-upgrade)
- pegaprox/core/keystore.py (_enforce_perms accepts S_IRGRP; docstring)
- docs/SECURITY.md (tier table + loader rejection wording)
- version.json, pegaprox/constants.py, web/src/constants.js, README.md
  (version bump to 0.9.10.3 / build 2026.05.15)
- web/index.html (frontend rebuild for new version constant)
2026-05-15 10:01:28 +02:00
MrMasterbay
edbd6e9fd0 release: v0.9.10 — SQLCipher full-DB encryption, LXC terminal, syslog scoping + dep hardening
Security
- Full-DB SQLCipher encryption (AES-256-CBC + HMAC-SHA512, format v4) on Linux x86_64.
  Auto-migrates plain DBs on first boot post-update (copy → sqlcipher_export →
  per-table row-count verify → atomic rename; timestamped .plain.bak retained).
  Graceful fallback to plain SQLite + Fernet field-encryption where the
  sqlcipher3-binary wheel isn't available (ARM/macOS/Windows).
- Multi-tier master-key loader: PEGAPROX_DB_KEY env → systemd LoadCredentialEncrypted
  → PEGAPROX_KEY_FILE → /etc/pegaprox/secret.key → ~/.config/pegaprox/secret.key →
  legacy CONFIG_DIR. Loose-perm files are skipped, never silently used. deploy.sh
  Step 5 generates the key outside config/ for fresh installs.
- Dependency floor bumps to clear pip-audit / Snyk findings: flask 3.0.3
  (werkzeug 3 RCE fix transit), flask-cors 6.0.0 (CWE-178 + 2 mediums),
  gevent 25.4.1 (CVSS 9.3 + 8.3 + 6.9), urllib3 2.5.0, paramiko 4.0.0,
  cryptography 46.0.7, h11 0.16.0, pyasn1 0.6.3, setuptools 78.1.1, zipp 3.19.1.
- 42-site reflected-content sanitizer (parse_pve_error html.escape) on Proxmox
  passthrough error paths across datacenter/vms/storage/static_files.

Features
- LXC dedicated text terminal — pct enter via PVE built-in termproxy API,
  wrapped through the existing SSH-WS transport. Server-side ticket mint, no
  shell exec on PegaProx side. vm.console permission gated, audit-logged.
- Cluster-scoped syslog viewer (#387, PR #399, contributed by @gyptazy, sponsored
  by credativ GmbH). Settings → Syslog Server tab with toggle; filters log rows
  by cluster's hostnames/nodes. i18n DE/EN/FR/ES/PT/KO.
- Corporate-layout enhancements across dashboard / VM modals / config tabs
  (~1.4k lines of new UI sources).

Operations
- Docker HEALTHCHECK start_period 15s→120s, retries 3→5 to give the
  in-process DB migration room on upgrade boot. Subsequent boots short-circuit.
- README: Aikido security audit badge.
- docs/SECURITY.md: new operator guide covering keystore tiers, migration tool,
  recovery story, and systemd LoadCredentialEncrypted (TPM2-bound) setup.
2026-05-13 19:18:13 +02:00