Gunnar

nordisk/Skidbladnir

.nornir/pki-guide.md

# pki — guide

> **Class:** `guide` · audience: a techie setting up per-machine PKI. The *what* is in
> [`pki-design.md`](pki-design.md); the *why* in [`pki-reasoning.md`](pki-reasoning.md).

## Self-generated certs (default, offline)

The default `pki` feature gives you a real ed25519 X.509 CA and leaves with no network:

```rust
use skidbladnir::pki::{MachineCa, verify_leaf};

let ca = MachineCa::generate("target-host")?;          // fresh CA, CN target-host.x14.local
let (leaf, key_pem) = ca.issue_leaf("holger", &["holger.local".into(), "127.0.0.1".into()])?;
// leaf.cert_pem + key_pem load straight into a rustls ServerConfig
assert!(verify_leaf(&leaf, &ca.verifying_key()));      // real signature check
```

Write `ca.ca_cert_pem()` to the target's trust store and hand each service its
`leaf.cert_pem` + `key_pem`.

For reproducible tests, seed the CA deterministically (still a real keypair):

```rust
let ca = MachineCa::from_seed("target-host", [0u8; 32]);   // same seed → same CA
```

## Drive it from a PkiSource

```rust
use skidbladnir::pki::{PkiSource, provision};
provision(&PkiSource::SelfGenerated, None)?;               // materialise self-signed PKI
```

## Use an existing Vault (feature `vault`)

```rust
# #[cfg(feature = "vault")] {
use skidbladnir::pki::{PkiSource, provision, vault::HttpVaultClient, VaultClient};

let client = HttpVaultClient::new("https://vault.internal:8200", token, "nordisk")?
    .mount("pki").ttl("72h");
let issued = client.issue("holger", &["holger.local".into()])?;   // POST /v1/pki/issue/nordisk
provision(&PkiSource::ExistingVault("nordisk".into()), Some(&client))?;
# }
```

A throwaway dev Vault for integration tests:

```rust
# #[cfg(feature = "vault")] {
let client = skidbladnir::pki::vault::TempVaultClient::spawn("nordisk")?;   // needs the `vault` binary
// … issue … ; teardown happens on drop
# }
```

## Gotchas

- Certs are trusted by **signature, not clock** — validity windows are deliberately wide (airgap
  targets have no reliable NTP). Do not rely on short expiries for revocation.
- The Vault variants are **seams**: without the `vault` feature (or without a `VaultClient`),
  `provision` errors clearly rather than pretending to issue.
- `SelfGenerated` needs the default `pki` feature; a `--no-default-features` build must add it back
  to mint certs.