Signing keys for Vaara audit exports
May 16, 2026 ยท View on GitHub
Vaara signs every audit-trail export with an Ed25519 detached signature. The signature lets a third party - auditor, regulator, internal conformity reviewer - verify that an exported trail came from you and has not been tampered with.
This document describes how to manage the signing key. It is written for two audiences:
- Engineers running local evaluations or demos. Skip to Local evaluation keys.
- Production deployments that submit trails to a regulator or auditor. Read Production keys first.
Threat model
A signed trail is a statement of the form:
"On date D, the holder of the private key with public-key fingerprint F attests that the exported record set is authentic."
Two failures matter:
- Forgery. An attacker who obtains the private key can produce signed trails that the verifier will accept as authentic.
- Tamper. An attacker who alters the trail file but does not have the key cannot produce a valid signature. This case is covered by the signature scheme itself.
The only attack that signing alone cannot stop is key compromise. Your operational goal is to make that expensive: keep the private key in hardware you control, rotate it on a schedule, and keep a public-key fingerprint ledger so old trails stay verifiable after rotation.
Production keys
Use one of the following, in order of preference:
1. Hardware security module (HSM) or cloud KMS
The private key never leaves the HSM. Signing happens by calling a signing API.
Supported providers:
- AWS KMS - create an
ECC_NIST_P256orEDDSAkey, grantkms:Signto the role your exporter runs as. - Google Cloud KMS - create an
EC_SIGN_ED25519asymmetric key. - Azure Key Vault - create an EC key with curve
P-256and thesignoperation enabled. - YubiHSM / Nitrokey HSM - Ed25519 keys with the
sign-eddsacapability.
For any of these, do not export the PEM. In the 0.4.x series
export_signed accepts a loaded Ed25519PrivateKey instance (or a PEM
path / PEM bytes) - integrate by loading the key material into that
object inside your signing host's memory, never on a developer laptop.
A pluggable signer-adapter interface (call an HSM/KMS sign API
without materializing the key) is tracked for a future release. Until
then, HSM integration requires a small wrapper in your deployment code
that fetches the key into a short-lived Ed25519PrivateKey.
2. Dedicated signing host
A small, locked-down machine (not a developer laptop) that:
- holds the PEM with
chmod 0400, - has only the signing user, no shell for other users,
- is network-isolated except for inbound trail-signing requests,
- logs every signing request to an append-only store.
This is a viable fallback if you cannot provision an HSM yet.
3. Local PEM (evaluation only)
The vaara keygen --dev helper writes a PEM to disk with 0600
permissions. Do not use it to sign trails you hand to a regulator.
It exists for:
- running the example scripts,
- recording a demo,
- writing integration tests.
Key rotation
Plan rotation before you need it. A concrete schedule:
- Every 12 months, or immediately on any suspicion of compromise.
- Generate the new key pair in the same place as the current one (HSM, KMS, etc.).
- Publish the new public-key fingerprint to the same out-of-band channel where your current public key lives (company website, signed release notes, regulator intake).
- Keep the previous public key available: a regulator who received a trail last quarter must still be able to verify it.
- Do not re-export old trails with the new key. Signatures are historical - each trail belongs to the key that signed it when exported.
Keep a fingerprint ledger, versioned in git:
# keys/public-key-fingerprints.md
2026-04-19 8f3c29b1a4d25e91... production, HSM slot 3
2025-04-18 2a1b88f7ce944301... superseded, rotated on schedule
2024-04-20 01a72dcbe5ff1aab... superseded, rotated on schedule
The fingerprint in this ledger must match the signer_pubkey_fingerprint
field that Vaara embeds in every trail manifest.
Distribution
The verifier needs your public key. Two channels:
-
Out-of-band (recommended). You hand the auditor the PEM file, or the fingerprint, via email, printed handoff, or the regulator's intake portal. The verifier passes
--pubkey signer.pemtovaara trail verify. -
Embedded in the zip. Every Vaara export embeds
signer_pubkey.peminside the zip. If no--pubkeyis passed the verifier uses the embedded one. This proves the trail is internally consistent but not that the signer is who they claim to be - the auditor should always verify the fingerprint matches something they received out-of-band.
Local evaluation keys
For demos, tests, and local evaluation only:
pip install 'vaara[export]'
vaara keygen --dev --out ~/.vaara/signer.pem
This writes:
~/.vaara/signer.pem(private key,0600)~/.vaara/signer.pem.pub(public key)
and prints the fingerprint.
The --dev flag is required. Without it, keygen refuses to write a
key so operators do not accidentally treat a development key as
production-grade.
To sign and verify a trail:
vaara trail export --trail trail.jsonl --out signed.zip --key ~/.vaara/signer.pem
vaara trail verify --zip signed.zip --pubkey ~/.vaara/signer.pem.pub
Offline verification
Regulators and auditors may run the standalone verifier with no Vaara install:
pip install cryptography
python scripts/verify_vaara_trail.py signed.zip --pubkey signer.pem
The script in scripts/verify_vaara_trail.py depends only on the
standard library and the cryptography package. Copy it to any machine.