Operating a node securely
The core defines how a passport is signed and trusted. The engine runs that in production, and this page covers what protects a live node: where the signing key lives, how access is controlled, and what the node does when something is missing or fails.
The signing key never leaves the node
Section titled “The signing key never leaves the node”The operator’s Ed25519 signing key is generated and held on their own infrastructure, encrypted at rest, and used inside the node process. The node signs passports itself, so there is no separate signing service and no key to hand over. Odal never holds the key; in a self-hosted deployment Odal has no access to the node at all. How the key is generated and protected is part of the core; see Security & cryptography and What Odal can and cannot see.
Access to the node
Section titled “Access to the node”A node accepts two kinds of credential. The public read path needs neither.
- API keys: for machines and integrations, presented as Bearer tokens. The full key is shown once, when it is created, and is never stored: the node keeps only a one-way hash of it and a short prefix used to look up the right record. A revoked or expired key is refused, and the comparison runs in constant time so a near-miss reveals nothing. Each key has a scope (read, write or admin), so it grants no more than its job needs.
- Admin login: a local username and password set in the node’s environment, used for first setup and for recovery. It is not stored in the database.
A key cannot revoke itself, so an automated rotation cannot lock you out halfway through. The admin login is the recovery path.
The public passport endpoint needs no credential. It only serves passports that are already published and gives no route into an operator’s data.
Least privilege in the database
Section titled “Least privilege in the database”The node connects to PostgreSQL with an application role that cannot change the schema and has no DELETE grant except on the import-job table, where a cleanup sweep needs one. Schema migrations run under a separate, privileged credential that is used only at start-up and never kept in the connection pool. The database also enforces the permanence guarantees itself: a trigger rejects edits to a locked passport, and the audit trail is append-only at the database level, so those rules hold even if the application code is wrong.
The node fails closed
Section titled “The node fails closed”A node refuses to start without its secrets: database credentials, the key-store passphrase and the signing domain. It also refuses the sample passwords and passphrase the repository once shipped, and an empty key-store passphrase. There are no insecure defaults; a misconfigured node does not start.
Node profiles
Section titled “Node profiles”NODE_PROFILE sets how strict a node is about the services it depends on for trust (rule checking, sealing, registry sync):
| Profile | What it accepts |
|---|---|
| unset (development) | Anything, with the trust posture logged |
sandbox |
Real or sandbox services (test authorities); refuses stand-ins |
production |
Only real services; refuses sandboxes and stand-ins |
Two development overrides exist, and both log a warning. ALLOW_DEV_CREDENTIALS=true accepts the sample credentials, under any profile. ALLOW_UNSIGNED_PLUGINS=true loads plugins without a signature, under the development profile only: a sandbox or production node refuses to start with it set, and a plugin loaded without a signature never counts as real rule checking in the trust posture. Never set either on a node anyone else can reach.
Product-group logic is sandboxed
Section titled “Product-group logic is sandboxed”A product group’s compliance logic runs in a Wasm sandbox with no filesystem and no network, capped at 64 MiB of memory and a fixed CPU budget (fuel metering). The plugin can read a clock and draw randomness. The clock is pinned to a single instant for the whole call, so a result cannot depend on when it ran. Randomness is real OS entropy and is not pinned: a fixed seed would make a plugin’s hash iteration order predictable without making any result more reproducible. A buggy or hostile plugin runs out of budget and is stopped; it cannot reach the signing key, the database or the rest of the node. These are the concrete limits behind the sandbox described in Security & cryptography.
The database is the source of truth
Section titled “The database is the source of truth”The database write comes first; everything else is a notification. Lifecycle events are published only after the database write commits, and a failure to publish is logged but not passed on, so a passport is published whether or not the event bus is healthy. Optional infrastructure that is missing does nothing rather than blocking the node, so a single-node deployment needs no message broker. Anything that consumes events should treat them as hints and read the database for the actual state.
One operator, one node
Section titled “One operator, one node”A node serves exactly one operator, with its own node and its own database. Operators are kept apart by separate deployments, not by a setting that could be misconfigured. There is no shared cluster, no code path across operators and no per-row tenant scoping to get wrong, so the usual multi-tenancy failures cannot happen. Serving many operators means running many nodes, which is handled at the infrastructure level, outside the node. See How the node works.
Reporting a vulnerability
Section titled “Reporting a vulnerability”The signing code is the core’s: the engine has no signature or key-derivation code of its own. It does hash for its own purposes, using SHA-256 for API-key and admin-password digests compared in constant time, because those belong to running the node rather than to passports. Dependencies are scanned for known advisories on every change. Suspected vulnerabilities go to security@odal-node.io under coordinated disclosure, never to a public issue first.
Read next
Section titled “Read next”- Permanence & retention: the long-term guarantees the node enforces.
- How the node works: the pipeline these protections surround.
- Security & cryptography: the cryptographic model the engine uses.
Information on this site is not legal advice. Legal noticePrivacy policy