Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

.nornir/pki-reasoning.md

pki — reasoning

Class: reasoning. Why the PKI layer is shaped this way. The descriptive shape is in pki-design.md.

Why trust by signature, not by clock

An airgapped target has no reliable time source — no NTP, often a drifting or reset RTC. Standard X.509 practice (short validity windows, expiry-driven rotation) assumes a trustworthy clock, which we do not have. So the design leans on signature verification as the trust primitive: verify_leaf checks the leaf's signature against the CA's ed25519 key, and validity windows are made deliberately wide (10 years for the CA). We reject short expiries as a revocation mechanism here because a clock-skewed target would spuriously reject valid certs — the failure mode is worse than the risk it guards against in a sealed environment.

Why SelfGenerated is the default and real, not a stub

The lean, offline core must be able to stand up a working TLS identity with no external service and no network — otherwise "airgap" is a lie the moment a service needs a cert. So SelfGenerated is a real ed25519 X.509 CA (via rcgen with the ring backend, pure Rust, no C/cmake) whose leaves actually load into a rustls ServerConfig. The earlier hand-rolled cert it replaced could not load into rustls — a cert that does not parse is not a cert. Making it real and default is what lets the offline path be honest.

Why Vault is a seam, not the default

Many nordisk deployments do have a Vault, and issuing from a shared CA is the right thing when one exists. But pulling a Vault HTTP client (reqwest) into the always-on core would fatten the embedded client that runs on the target device and couple its build to a network stack it may never use. So Vault lives behind the vault feature as a VaultClient trait with two impls (HttpVaultClient against a real Vault, TempVaultClient for tests). provision errors clearly when a Vault source is named without a client — an honest "you asked for Vault but gave me none" rather than a silent fallback that would mask a misconfiguration.

Why ring, not aws-lc-rs

The rcgen and x509-parser deps use the ring crypto backend rather than aws_lc_rs. ring keeps the whole PKI path pure-Rust with no C/cmake build step, matching the workspace's rustls-via-ring posture — so the airgap core cross-compiles cleanly and builds on a headless target without a C toolchain. aws-lc-rs would drag a C build into the lean core.