NovaSeal Configuration Reference
Status: Works today (NovaSeal v0.1+, ADR-0041)
This document is the single source of truth for configuring NovaSeal: the
novaseal.yaml config file, all environment variables, path resolution order,
and deployment-specific patterns.
Related documents:
- NovaSeal Key Management Guide — key generation, rotation, HSM setup
- NovaSeal API Stability Guarantee — what changes are breaking
- Operator Guide — cluster and Docker deployment context
- CLI Reference § nova seal / nova verify
Table of contents
- Configuration file —
novaseal.yaml - Profiles
- Merkle log database (
merkle_db) - Environment variables — complete reference
- Discovery order for
novaseal.yaml - Troubleshooting
1. Configuration file — novaseal.yaml
NovaSeal is opt-in: if no novaseal.yaml is found, NovaSeal is silently
disabled and nova capture proceeds without signing. This is the correct
behavior for local development.
The file is discovered automatically (see §5). A minimal example for local use with a file-based ECDSA P-256 key:
# ~/.novafabric/novaseal.yaml
profile: local
key_path: ~/.novafabric/seal.key # ECDSA P-256 private key (PEM, PKCS#8)
cert_path: ~/.novafabric/seal.crt # X.509 certificate for the key
tsa_url: https://freetsa.org/tsr # RFC 3161 timestamp authority (optional)
merkle_db: ~/.novafabric/novaseal-merkle.db # SQLite Merkle log (optional)All path values are expanded with ~ resolution. All fields except
profile, key_path, and cert_path are optional.
1.1 TSA fallback list (tsa_urls)
Status: Works today (REG-ADR-007). By default tsa_url is the only TSA
tried. For production and EU-regulated deployments where a single TSA being
unreachable should not block sealing, configure an ordered fallback list
instead:
# ~/.novafabric/novaseal.yaml
profile: local
key_path: ~/.novafabric/seal.key
cert_path: ~/.novafabric/seal.crt
tsa_urls: # tried in order; first success wins
- https://tsa.your-qtsp.example/tsr # primary — e.g. a QTSP for eIDAS Art. 41(2)
- https://freetsa.org/tsr # fallback — public, non-qualified
merkle_db: ~/.novafabric/novaseal-merkle.dbIf tsa_urls is omitted, it defaults to a single-entry list containing
tsa_url — existing configs with only tsa_url set need no changes. When
tsa_urls has more than one entry, each is tried in sequence; a TSA that
returns an error, times out, or is unreachable is skipped and the next one
is tried. Timestamping is already best-effort in NovaSeal (a capsule seals
successfully without a timestamp token if the TSA request fails) — the
fallback list only widens how many TSAs must fail before that happens.
tsa_urls applies identically across all four profiles (§2) — it only
affects the timestamp request, not the signing key/certificate.
Not yet built: fallback is sequential with no configurable per-TSA timeout or retry count (each URL gets one attempt at the module's fixed 30-second HTTP timeout before moving to the next) — sufficient for a small fallback list, but there is no automated benchmark validating this against a specific deployment's real network conditions (e.g. an air-gapped site with a local relay TSA); that assessment is left to the operator.
2. Profiles
The four profiles below are configured through novaseal.yaml's profile:
field. Two further signing backends exist outside this file, selected
instead via a CLI flag on nova seal sign/nova verify — a keyless
--backend sigstore (ADR-0071) and the ADR-0055 x509 cert-pinned identity
(currently a library API, not yet a CLI flag); see NovaSeal Key Management
§2.3–2.4
for both.
2.1 local — ECDSA P-256 file key
The default for on-premises and laptop deployments. The private key lives on disk, optionally encrypted by the OS keychain or a secrets manager.
profile: local
key_path: /path/to/seal.pem # required — PKCS#8 PEM, ECDSA P-256
cert_path: /path/to/seal.crt # required — PEM certificate
tsa_url: https://freetsa.org/tsr # optional; omit to skip RFC 3161 timestamps
merkle_db: /path/to/merkle.db # optional; see §3Generate a key and self-signed certificate:
openssl ecparam -name prime256v1 -genkey -noout | \
openssl pkcs8 -topk8 -nocrypt -out ~/.novafabric/seal.key
openssl req -new -x509 -key ~/.novafabric/seal.key \
-out ~/.novafabric/seal.crt \
-days 3650 -subj "/CN=NovaSeal-Local"2.2 aws_kms — AWS KMS asymmetric key
Uses an AWS KMS ECDSA_SHA_256 key. Requires the [seal-aws] optional extra:
pip install novafabric[seal-aws].
profile: aws_kms
kms_key_id: arn:aws:kms:us-east-1:123456789012:key/mrk-abc123 # required
aws_region: us-east-1 # optional; default us-east-1
cert_path: /path/to/cert.pem # required — certificate for the KMS public key
tsa_url: https://freetsa.org/tsr # optional
merkle_db: /path/to/merkle.db # optional; see §32.3 azure_kv — Azure Key Vault
Uses an Azure Key Vault EC P-256 key. Requires [seal-azure].
profile: azure_kv
vault_url: https://myvault.vault.azure.net/ # required
key_name: my-ec-key # required
cert_path: /path/to/cert.pem # required
tsa_url: https://freetsa.org/tsr # optional
merkle_db: /path/to/merkle.db # optional; see §32.4 gcp_kms — GCP Cloud KMS
Uses a GCP Cloud KMS EC P-256 asymmetric signing key. Requires [seal-gcp].
profile: gcp_kms
key_version_name: projects/P/locations/L/keyRings/R/cryptoKeys/K/cryptoKeyVersions/1
cert_path: /path/to/cert.pem # required
tsa_url: https://freetsa.org/tsr # optional
merkle_db: /path/to/merkle.db # optional; see §33. Merkle log database (merkle_db)
NovaSeal maintains a tamper-evident SQLite Merkle log of all seal operations.
The merkle_db field in novaseal.yaml controls where this file lives.
3.1 Path resolution order
All three NovaSeal call sites in NovaFabric (serve/app.py diagnostic check,
serve/app.py SealTab endpoints, server/routes/seal.py policy store) resolve
the Merkle DB path through a single canonical function:
novafabric.trust.novaseal.config.resolve_merkle_db_path().
Precedence (highest to lowest):
| Priority | Source | When to use |
|---|---|---|
| 1 | NOVAFABRIC_SEAL_DB_PATH env var |
Explicit override; CI/test environments; Postgres URL (postgres://..., experimental — see §3.4) |
| 2 | merkle_db: field in novaseal.yaml |
Production config — set this for non-default paths |
| 3 | ~/.novafabric/novaseal-merkle.db |
Default for local laptop use |
If novaseal.yaml is not found or cannot be parsed, priority 2 is skipped and
priority 3 applies.
3.2 Docker and container deployments
In Docker the default home directory and NOVAFABRIC_HOME are typically
different from the host. Set merkle_db explicitly in novaseal.yaml so the
path always resolves to the mounted volume:
# /data/nova/novaseal.yaml (mounted into the container)
profile: local
key_path: /data/nova/keys/seal.key
cert_path: /data/nova/keys/seal.crt
merkle_db: /data/nova/novaseal-merkle.db# docker-compose.yml (excerpt)
services:
nova-serve:
environment:
NOVAFABRIC_SEAL_CONFIG: /data/nova/novaseal.yaml
volumes:
- nova-data:/data/novaSetting NOVAFABRIC_SEAL_CONFIG ensures the config is found regardless of
where the container's home directory is, which fixes the nova doctor
novaseal_db FAIL that would otherwise appear when NOVAFABRIC_HOME and
~/.novafabric diverge.
3.3 SLURM and shared-filesystem deployments
For multi-node SLURM jobs, merkle_db must point to a path on the shared
filesystem (Lustre, GPFS, NFS) so all compute nodes write to the same log:
# /home/$USER/.novafabric/novaseal.yaml
profile: local
key_path: /lustre/project/novafabric/keys/seal.key
cert_path: /lustre/project/novafabric/keys/seal.crt
merkle_db: /lustre/project/novafabric/novaseal-merkle.dbSQLite's WAL mode handles concurrent appends from multiple workers within a single job. For large-scale parallelism (>100 concurrent writers), the Postgres backend (§3.4) is the appropriate path.
3.4 Postgres backend (experimental, Scale-S4)
Experimental — implemented (ROADMAP Scale-S4). SQLite remains the default;
the Postgres backend is opt-in via a Postgres DSN. The merkle-log factory
(open_merkle_log) routes postgresql:// / postgres:// URIs to the
PostgresMerkleLog backend.
The merkle_db field accepts a Postgres connection URL:
merkle_db: postgres://user:pass@pghost/novafabric_sealThe NOVAFABRIC_SEAL_DB_PATH env var also accepts this format for
programmatic override without editing novaseal.yaml.
4. Environment variables — complete reference
| Variable | Default | Description |
|---|---|---|
NOVAFABRIC_SEAL_CONFIG |
~/.novafabric/novaseal.yaml |
Path to novaseal.yaml. Takes precedence over the default location. Set this in Docker/K8s to point to the config on the mounted volume. |
NOVAFABRIC_SEAL_DB_PATH |
— | Explicit Merkle DB path (or a postgresql:// DSN for the experimental Postgres backend, §3.4). Overrides merkle_db in novaseal.yaml. Intended for CI/test environments. |
NOVA_BYPASS_NOTIFY_URL |
— | Webhook URL for bypass-event notifications (see ADR-0059). |
NOVASEAL_KMS_ENDPOINT |
— | NovaSeal KMS endpoint for collector batch signing (cluster-scale, experimental). |
Interaction between NOVAFABRIC_SEAL_CONFIG and NOVAFABRIC_SEAL_DB_PATH:
If both are set, NOVAFABRIC_SEAL_DB_PATH wins for the Merkle DB path (priority 1),
even if novaseal.yaml (pointed to by NOVAFABRIC_SEAL_CONFIG) also has a
merkle_db field. The YAML merkle_db only applies when the env var is absent.
5. Discovery order for novaseal.yaml
load_signing_profile() searches in this order:
NOVAFABRIC_SEAL_CONFIGenv var — if set and the file exists, use it. If set but the file is missing, raiseSealConfigError(fail fast; do not silently fall through to the default).~/.novafabric/novaseal.yaml— if it exists, use it.- No config found — NovaSeal is disabled;
load_signing_profile()returnsNone.
This means NovaSeal is completely opt-in at the individual user level.
A system administrator can pre-create ~/.novafabric/novaseal.yaml in the
user's home directory (e.g., via SLURM prologue or dotfiles management) to
enable NovaSeal transparently.
6. Troubleshooting
nova doctor shows novaseal_db FAIL
The diagnostic check calls resolve_merkle_db_path() and tests whether the
returned path exists. Common causes:
| Symptom | Cause | Fix |
|---|---|---|
Path shown is /data/nova/novaseal-merkle.db but the file isn't there |
NOVAFABRIC_HOME=/data/nova in Docker, but novaseal.yaml not found or has no merkle_db — so the old default was used incorrectly |
Set merkle_db: /data/nova/novaseal-merkle.db in novaseal.yaml and set NOVAFABRIC_SEAL_CONFIG to its path |
Path shown is ~/.novafabric/novaseal-merkle.db but the file isn't there |
No capsule has been sealed yet — the DB is created on first nova seal propose |
Run a seal operation, or pre-create the file: touch ~/.novafabric/novaseal-merkle.db |
novaseal_db FAIL after setting NOVAFABRIC_SEAL_DB_PATH |
The env var path doesn't exist yet | Create the parent directory and touch the file, or run a seal operation |
SealConfigError: NOVAFABRIC_SEAL_CONFIG points to missing file
The env var is set but the file at that path doesn't exist. Either create the
file or unset the env var to fall back to ~/.novafabric/novaseal.yaml.
NovaSeal silently disabled — no seal directory in capsule
load_signing_profile() returned None (no config found). Create
~/.novafabric/novaseal.yaml or set NOVAFABRIC_SEAL_CONFIG.
Merkle DB path differs between nova seal and nova doctor
All code paths now use resolve_merkle_db_path() from
novafabric.trust.novaseal.config. If you observe a discrepancy, verify that
no stale NOVAFABRIC_SEAL_DB_PATH env var is set in one shell but not another.
TSA timeout or tsa_url errors
The default https://freetsa.org/tsr is a free public TSA with rate limits.
For production, use an organizational or commercial TSA. Set tsa_url: in
novaseal.yaml. To disable RFC 3161 timestamps entirely, omit the field —
NovaSeal still signs with ECDSA but without a timestamp token. If a single
TSA being occasionally unreachable is the actual problem, configure a
fallback list instead of (or as well as) switching providers — see
§1.1 TSA fallback list.