Skip to content

RivetMSP 26.10.14

Choose a tag to compare

@TheTractorHacker TheTractorHacker released this 11 Oct 05:22
· 12 commits to master since this release

Ports RivetIT's released adoption (26.10.35 plus the 26.10.37 secret-box fix) of RivetCore 1.0.0-rc.10 RivetCore\Crypto (ADR-011) for stored secrets. DB 2.6.87 (one idempotent step gated on 2.6.86: widens the encrypted
columns so the new envelope fits, adds settings.config_vault_v3_enabled (0), config_vault_dek_wrap, config_vault_v3_prepared_at and api_tokens.token_enc_dek; no stored value changes; db.sql carries it and a fresh
import equals a migrated database). Nothing changes on an existing install until an administrator creates the key file; the credential vault stays on the legacy format until its flag is switched on.
Read docs/KEY_MANAGEMENT.md before deploying.

Deploy notes (in this order; take a database dump first):

  1. Back up the database, pull this tag and run composer install --no-dev --no-plugins --no-scripts (nothing new is installed; the lock is unchanged).
  2. php scripts/update_cli.php --update_db (2.6.86 to 2.6.87). Safe to run before anything else; the app keeps working on the config.php key exactly as before.
  3. As root, create the key file: sudo php scripts/keys_cli.php generate. It creates /etc/rivetmsp 0755 (the web user must be able to traverse it) and keys.json root:www-data 0640, with the config.php key as kid k1. Check with php scripts/keys_cli.php status: it must not say "NOT REACHABLE".
  4. Take an offline copy of /etc/rivetmsp/keys.json now, apart from the dump and the backup passphrase.
  5. Dry run, then move everything: php scripts/rewrap_cli.php --dry-run, php scripts/rewrap_cli.php (repeats until a pass changes nothing; resumable). php scripts/keys_cli.php status --inventory shows the result.
  6. Leave the credential vault flag off (config_vault_v3_enabled stays 0; scripts/vault_v3_cli.php is for a later, deliberate step).
  7. Rollback: set $config_crypto_v3_settings = false; in config.php (new writes are ENC2: again; v3 values already written stay readable by this release). Downgrading the code needs the values moved back first, or a restore of the pre-upgrade dump.
  • Settings and two-factor seeds. encryptSetting() / decryptSetting() (same signatures, an optional context) go through RivetMSP\Crypto\SettingsCrypto / RivetCore's SettingsVault. With a key file, new values are v3:<kid>:...; ENC2:, ENC: and cleartext keep reading and move to v3 lazily (the settings row) and with the tool. users.user_token seeds are v3 of the totp purpose bound to the user. A value that cannot be opened reads as empty (logged once, never the value); an unknown or damaged envelope (v4:, ENC3:, a truncated v3:) now fails closed instead of being handed back as if it were cleartext; true legacy cleartext still reads. Flags $config_crypto_v3_settings, $config_crypto_v3_totp.
  • Tooling. scripts/keys_cli.php (status, generate, fingerprint, add-key, set-active, retire), scripts/rewrap_cli.php (one RewrapSource per encrypted column; Core's Rewrapper: dry run, resumable, compare-and-set, never truncates a too-narrow column, one audit row per column and run) and Administration > Security > Encryption keys. The registry (src/Crypto/ColumnRegistry.php) is derived from secStragglerColumns() and also covers the RMM module's secrets (signing key, Mesh login key, queued job secrets, secret custom fields), including a composite-key source.
  • The key file directory. generate as root creates the directory 0755 and the file root:www-data 0640; the installer (deploy/install.sh) creates it as root after setup; status, the CLI and the panel say KEY FILE NOT REACHABLE (with the command that fixes it) when the web user cannot traverse the directory or read the file, instead of showing a plain legacy install.
  • Credential vault v3 (flag config_vault_v3_enabled, default off, scripts/vault_v3_cli.php): fields sealed with the vault data key (AAD credential:<id>:<field>), per-user vw3: wraps at the next password login, mobile tokens wrap the data key, writes (including a restore from an uploaded backup) finalised to v3. Not enabled by this release.
  • Recovery. The backup manifests (in-app zip and deploy/backup.sh) keep the fingerprint formula and add the key ring by kid and fingerprint (no key material); deploy/restore.sh and deploy/install.sh --restore-from accept --key-file / --restore-key-file; the setup wizard restore names the missing keys; the restore drill reports "Key file for this backup" and opens v3 samples. The key file is never in an archive: escrow it separately.
  • Ciphertext prefix checks accept v3: everywhere (a v3 value would otherwise be mistaken for cleartext): secIsWrapped(), the cleartext-row SQL, the webhook URL masking on the list and edit pages, the drill's secret check, EndpointSecretBox (already since 26.10.13). A cleartext vault key or TOTP seed is wrapped in its own context. decryptSetting() loads Composer's autoloader itself, so a cron script that never did cannot silently read v3 values as empty.
  • Tests: tests/crypto_settings.php, crypto_rewrap.php, crypto_vault.php, crypto_panel.php, tests/crypto_msp_integration.php (prefix sites, fail-closed, key file access, TOTP login over HTTP, cron/mail_queue.php against a fake SMTP server with the password and an XOAUTH2 token, webhook queue delivery with the HMAC, every settings secret, provider credentials, all after a real rewrap), tests/crypto_rmm_after_rewrap.php (the RMM signing key signs a job over HTTP after a real rewrap; Mesh key, job and custom field secrets, Tactical / Level / Action1 / Sophos credentials; an unreadable key file), and RivetCore's RewrapSourceConformanceTestCase for the integer and string key sources plus a composite-key test.