You are here: start » en » Internal Documentation » DokuWiki extensions (WvdS) » WvdS Vault

WvdS Vault

Vault is the one place for the operator secrets of the package family: stored encrypted, with an expiry date, hand-over rotation and an access log. Without it, credentials sit in as many places as there are packages. The package is meant for operators who have to enter secrets, change them and prove how they were used.

Getting started

Common tasks

What you want For whom Where you do it Instructions
enter or change a secret operators Administration > Vault Five schemes
rotate a secret as planned operators Administration > Vault Rotation
change the key source operators Changing the key source
prove who accessed what and when operators Administration > Vault The access log
understand the second factor before access operators Second factor
know what the vault does not do operators What the vault does not do

Purpose

One place for the operator secrets of the suite: stored encrypted, with an expiry date, hand-over rotation and an access log. Without it, credentials sit in as many places as there are plugins, in as many forms as their authors have invented — and at least one of those is plain text in conf/local.php.

Registered service (see Core): vault.secrets. The entries live via Storage in data/dwdo/.

No encryption method was missing — a place was. That is this plugin's job, and the boundary in the next section follows from it.

What the vault explicitly does not do

The boundary comes first, because with a vault it is the most important thing to know.

With the default key source salt the master key is derived from the wiki's instance salt. That salt lives under data/meta/ — the same branch as the vault database under data/dwdo/.

Measured, not assumed: an ordinary backup of data/ contains the key and the ciphertext together. Whoever holds that archive reaches the secrets. This plugin does not protect against that.

What it does protect against is everything short of that: a page that says too much, a file permission set too wide, a plugin that logs its own configuration, a database handed to a developer.

This class of exposure can be left entirely by choosing another key source — see Configuration. env and file put the key outside data/ and therefore outside the wiki backup.


Five schemes, one decision by the operator

A plugin that needs a password does not get a value, it gets a reference. Which source an installation uses is therefore decided by the operator, not by the author of each individual plugin.

Reference Meaning
vault:{id} Entry from this vault
env:{name} Environment variable
file:{path} File below the directory configured in file_root
enc:… Value stored encrypted inline
plain:… Plain text, explicitly marked as such

Resolution happens from within your own plugin through SecretRef; the result distinguishes two cases that must not be conflated:

Result Meaning
null nothing was configured
SecretRefException something was configured and could not be redeemed
These are different problems. “No password stored” is a setup step still missing; “reference cannot be redeemed” is a fault in an existing setup. A message that treats both alike sends the operator in the wrong direction.

Configuration

Setting Default Meaning
keysource salt Origin of the master key: salt, env or file
keysource_ref empty Variable name for env, file path for file; no effect with salt
file_root empty Root directory that file: references must stay inside. Empty disables the scheme entirely
log_page_size 100 Rows per page in the access log
log_keep_days 365 Age at which access records expire; 0 keeps them forever
file_root is empty by default and therefore fail-closed. A reference is configuration supplied by the operator; without a root that confines it, file: would be a tool for reading arbitrary files dressed up as a secret.
salt is the default because it needs no setup — and it is the weakest of the three. env and file can both be copied to another machine and another operating system. That very requirement rules out machine-bound stores (DPAPI, TPM, keychain): a vault whose key cannot leave the computer is irrecoverable after a hardware failure — backup present and unreadable.

Changing the key source

Changing it is supported and harmless in itself: every value carries a fingerprint of the key it was encrypted under, never the key itself. Existing entries therefore keep decrypting, and new writes use the new source.

The order is binding:

  1. Change the setting.
  2. Run the re-encryption on the administration screen.
  3. Only then remove the old key material.

The screen reports through keyUsage() how many entries still sit under the old fingerprint. Those are exactly the ones that would become unreadable if it were removed too early.


Rotation: two slots, four steps

An entry has two slots. A new value is first staged and switches nothing; only promoting it makes it the valid value.

  • stage() — stage a new value, running operations keep using the old one
  • promote() — make the staged value the valid one
The order is stage → verify → promote → revoke at the provider. Every other order has a window in which the answer is wrong.

The access log

One line per read, write and promote, carrying actor, entry, operation and result — and never a value. That is the difference between a vault and an encrypted file.

The vault.secrets service hands out reading only (read(), has()) and binds the actor. A plugin that needs a password can therefore neither rotate one nor attribute a read to somebody else.

Cleanup runs through the indexer's task execution, that is, on ordinary page views. On a wiki without traffic the records therefore simply stay.


Second factor before every access to secret material

Secured through the Identity Plugin Contract v1 (contract description): a bridge do=wkvault_stepup with a hard-wired list of categories.

Category Applies to
create Creating an entry
rotate Staging a value
delete Deleting an entry
rekey Changing the key source and re-encrypting everything

The check runs twice — on read when the screen is drawn, and again on submit — and in both cases in addition to the DokuWiki access list, never in its place. Without wkidentity the package behaves unchanged.

The bridge never accepts a requirement supplied by the caller, only a name from its own list; an unknown name yields a refusal, never “no requirement”.

Since 9 August 2026 “delete” also carries the danger rank. Before that, the package's most destructive action sat on a button rank no stylesheet defines — it was therefore unstyled and carried no visual signal, right next to a highlighted “promote”. A missing marking looks like a decision, and it was not one.

Prerequisites

  • PHP 8.2 or newer.
  • Core for the service registration and Storage for the entries — both required, not optional.
  • Administrator rights for the administration screen.

The schema creates two tables, “vault.secret” and “vault.zugriff”, each idempotently. The dot is part of the name and separates the module, now that all modules keep their tables in one shared database; it must always be quoted in SQL, because SQLite otherwise reads it as a database separator and does not find the table.


Limits

  • The default key source shares its backup with the data — see above.
  • An expired secret is still delivered. Expiry is a prompt, not a safeguard: refusing delivery on a due date would bring mail dispatch, databases and repository access to a halt simultaneously, and for an administrative reason at that.
  • Staging switches nothing. Only promoting does. That is the design, not a shortcoming.
  • The vault cannot revoke anything at the provider. Completing a rotation by invalidating the old credential remains the operator's job.
  • Lost key material means lost values. By design there is no recovery path.
  • Cleanup depends on the wiki's indexer.

Package details

Plugin: wkvault
Namespace: lib/plugins/wkvault/
Author: Wolfgang van der Stille Wolfgang.van.der.Stille@gmail.com (The White Knight Labs)
License: GPL 2

en/wiki/dwe/wkvault/start.txt · Last modified: by 0.0.0.0