:navigation-title: Decommissioning .. include:: /Includes.rst.txt .. _operations-decommissioning: =============== Decommissioning =============== Retiring a vault, or an installation that contains one. The order matters, and one step is irreversible by design. .. _operations-decommissioning-secrets: Secret disposal =============== .. warning:: **``vault:delete`` is a soft delete.** :php:`SecretRepository::delete()` sets ``deleted = 1`` and updates ``tstamp``; the row — with its ciphertext, its wrapped DEK and its nonces — stays in ``tx_nrvault_secret``. The same is true of ``vault:cleanup-orphans``, which routes through the same :php:`VaultService::delete()`. There is no hard-delete path in the extension. Do not read "deleted" as "gone". That is the right default for a live system: it keeps the operation auditable and reversible, and the row is unreadable to anyone without the master key anyway. It is the wrong assumption when decommissioning. For actual disposal you have two options, and they compose: **Crypto-erasure (recommended).** Destroy the master key and every secret in the vault becomes permanently unreadable in one step — including soft-deleted rows, including rows in every backup already taken. This is the only measure that reaches copies you no longer control. See :ref:`operations-decommissioning-keys`. **Row removal (for completeness).** Drop or truncate the tables at the database level once the audit-retention obligations below are satisfied: .. code-block:: sql :caption: Only after the evidence export is complete and verified -- Secrets, including soft-deleted rows, and their two ACL relation -- tables. Dropping only the secret table leaves the MM rows behind. DROP TABLE tx_nrvault_secret; DROP TABLE tx_nrvault_secret_begroups_mm; DROP TABLE tx_nrvault_secret_writegroups_mm; -- Audit chain. Check your retention obligations FIRST. DROP TABLE tx_nrvault_audit_log; -- Vault state also lives in the core registry: the chain tip anchor, -- and the break-glass session plus per-sink delivery state. DELETE FROM sys_registry WHERE entry_namespace = 'tx_nrvault_audit_anchor'; DELETE FROM sys_registry WHERE entry_namespace = 'tx_nrvault'; .. note:: Row removal on its own is weaker than it looks: database backups, replicas, binlogs, filesystem snapshots and storage-level copies keep the ciphertext for as long as their own retention allows. Crypto-erasure is what makes those copies worthless. Do both if the policy demands it; do crypto-erasure if you can only do one. .. _operations-decommissioning-rotate-out: Rotate credentials out, do not just delete them =============================================== A secret in the vault is a *copy* of a credential that also exists in the system it authenticates against. Deleting the vault copy does not revoke anything. Before disposal, for every secret still in use: rotate the credential at its origin — the API provider, the SMTP relay, the OAuth client, the deploy key — so that the value the vault held stops working. Then dispose of the vault copy. In that order: a rotation performed after the vault is gone has to be done without the ability to read what is being replaced. .. _operations-decommissioning-evidence: Final evidence export ===================== Do this **before** anything destructive. Once the master key is gone, the audit chain can no longer be verified — the HMAC key was derived from it — so a verification run after key destruction proves nothing. #. **Verify the chain while the key still exists**, and keep the output: .. code-block:: bash vendor/bin/typo3 vault:audit-verify > decommission-verify.txt #. **Publish a final anchor**, so the tip is witnessed externally at the moment of decommissioning: .. code-block:: bash vendor/bin/typo3 vault:audit-anchor #. **Export the audit log** in full, over the entire retained period, with the hash columns included — ``uid``, ``previous_hash``, ``entry_hash``, ``hmac_key_epoch``. Without them the export is a log, not evidence. #. **Collect the external evidence** from where it actually lives: the anchor file, the syslog archive, the SIEM's retained records. This is the half the installation cannot fabricate, and after decommissioning it is the only half left. #. **Record the decommissioning itself** — date, operator, which artefacts were exported, which tables were dropped, when and how the key was destroyed. A ``TABLE_RESET`` finding against the final anchor is indistinguishable from a malicious reset without this record. :ref:`auditor-evidence-collection` lists the artefacts in the form an assessor expects. .. _operations-decommissioning-retention: Retention obligations versus deletion ===================================== These pull in opposite directions and nr-vault cannot resolve the conflict for you — it can only make sure you notice it. * **The secrets are the deletion obligation.** Credentials have no reason to outlive the system that used them, and a retained ciphertext is a retained risk for as long as any copy of the key might exist. * **The audit log is the retention obligation.** It is the record of who accessed which credential and when — frequently the artefact an audit regime requires to be kept, and often for years. It contains no secret values. **They are separable, and separating them is the answer.** Destroy the key and drop ``tx_nrvault_secret``; keep the exported audit evidence for as long as policy requires. The exported chain remains internally verifiable — each row's ``previous_hash`` still links to its predecessor — but note honestly what is lost: **without the master key, HMAC recomputation is no longer possible**, so from epoch 1 upwards the export becomes a *sequence* whose links can be inspected rather than a chain whose authenticity can be re-proved. That is why the verification output from step 1 above matters: it is the last point at which authenticity was demonstrable, and it must be captured then, not later. .. note:: ``tx_nrvault_audit_log`` also holds personal data — ``actor_username``, ``ip_address``, ``user_agent``. A deletion request under data-protection law collides with the tamper-evident design: editing or removing a row breaks the chain by construction, which is the entire point. :ref:`adr-017-audit-metadata-retention` is where that trade-off is recorded; resolve it as a policy decision before decommissioning, not during. .. _operations-decommissioning-keys: Key destruction =============== Irreversible. There is no escrow and no vendor-side reset — see :ref:`security-known-limitations-key-loss`. .. list-table:: :header-rows: 1 :widths: 16 84 * - Provider - How to destroy the key * - ``typo3`` - Rotate or remove ``SYS/encryptionKey`` in :file:`config/system/settings.php`, and destroy every backup of that file. **Harder than it sounds** — the config directory is usually in more backups than anyone expects, and ``encryptionKey`` is also used by TYPO3 core for unrelated purposes, so removing it has effects beyond the vault. * - ``file`` - Delete the key file and every copy, including the separate key backup. On a copy-on-write filesystem or a storage layer with snapshots, deletion is not erasure — destroy the snapshots too. * - ``env`` - Remove the variable from the injection mechanism and restart. Then check where it was *also* recorded: CI secret stores, deployment manifests, container inspection output, shell history. * - ``transit`` - **The cleanest case.** Delete the transit key in HashiCorp Vault (or revoke every policy granting ``decrypt`` on it) and the locally stored wrapped blob becomes undecryptable immediately — including in every backup that contains it. Then delete the wrapped file as well. #. Confirm the evidence export is complete and stored elsewhere. #. Confirm no other installation shares the key material. A key file copied to a staging system is still a live key. #. Destroy the key. #. Verify destruction by attempting a read: a probe decrypt must now fail with ``Master key not found at: …`` or ``Authentication failed - data may have been tampered with``. A successful read means a copy survived somewhere — find it. #. Drop the tables, if row removal is also required. .. _operations-decommissioning-cleanup: Installation cleanup ==================== * **Remove the sinks** last, not first: they are what records the decommissioning steps. Turn off ``auditSinkWebhookEnabled`` and friends only after the final anchor has been published. * **Unschedule the tasks** — the audit anchor and audit verify scheduler tasks, and orphan cleanup — or they will start failing loudly against a vault that no longer exists. * **Revoke the grants.** Remove the ``tx_nrvault:*`` custom options from ``be_groups``, so a later reinstall does not silently inherit a permission model nobody reviewed. * **Unpin the settings.** Remove the :php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['nrVault']` entries from :file:`config/system/additional.php`, and the extension configuration block itself from :file:`config/system/settings.php` — the pins are only the part that lives in ``additional.php``. * **Remove the extension**, and remember that removing it does not remove its tables. * **Clean up the KMS side** if ``transit`` was used: revoke the token, remove the policy, delete the transit key.