geth/docs/sigchain-keychain.md

130 lines
4.9 KiB
Markdown

# Geth Keychain And SSHSIGCHAIN
## Purpose
The geth keychain is the local identity-plane operation log for admin SSH keys,
users, devices, nodes, agents, and endpoint bindings. The daemon stores these
operations in SQLite and synchronizes authorized records over Iroh. Reducing
the operation log produces the current keychain view used by node management,
authorization, and OpenSSH `allowed_signers` projection.
[`sshsigchain.md`](sshsigchain.md) specifies SSHSIGCHAIN, the only portable
signed-chain format in this repository. It is deliberately separate from the
current local keychain operation log: SSHSIGCHAIN starts with an explicit
out-of-band trust tuple, has a strict sequence and hash link, and never uses a
downloaded `allowed_signers` file as a trust root. The previous test-only
static JSONL publication format was removed.
## Local keychain model
The durable local log contains `KeychainOp` records and their
`KeychainOpSignature` records. Every operation has a deterministic canonical
binary signing payload under the `geth.keychain.v1@geth.local` namespace.
JSON is an API and storage representation, never the signed payload.
Important operation kinds are:
- `KeychainInit`
- `AdminKeyAdd`, `AdminKeyRevoke`
- `UserAdd`, `UserRename`, `UserRevoke`
- `DeviceAdd`, `DeviceRevoke`, `DeviceKeyAdd`, `DeviceKeyRevoke`
- `NodeAdd`, `NodeRename`, `NodeRevoke`
- `NodeEndpointAdd`, `NodeEndpointRevoke`
- `AgentBind`
`AdminKeyAdd` carries the OpenSSH public key material used to reconstruct the
active `allowed_signers` view. Local operation and signature identities are
append-only: an existing identity with different bytes is rejected rather than
replaced.
## Local signatures
An operation signature contains its operation ID, signer key fingerprint,
signer public key, SSHSIG namespace, OpenSSH signature bytes, and creation
time. geth signs through OpenSSH, for example:
```sh
ssh-keygen -Y sign -n geth.keychain.v1@geth.local -f <signing-key> <payload>
```
`<signing-key>` may be a local private key, an OpenSSH security-key stub, or a
public key whose private half is available through `ssh-agent`. The daemon does
not store private keys or passphrases.
Local verification accepts an operation only when a signature from an admin
key in the previously accepted local view verifies over the canonical payload.
This is useful for the local Iroh-synchronized operation log, but it is not a
portable SSHSIGCHAIN history and MUST NOT be presented as one.
## SSHSIGCHAIN keychain profile
Geth's SSHSIGCHAIN profile identifier is `geth.keychain.sshsigchain.v1` and its
SSHSIG namespace is `sshsigchain.v1`. Its canonical binary payload is a
versioned mirror of a keychain operation; it is separate from the
human-facing, internally tagged JSON API type so a decoder can prove one unique
payload encoding.
The profile requires:
- sequence zero to be `KeychainInit` signed by the operator-pinned root key;
- sequence one to be an `AdminKeyAdd` recording that root key;
- every following signer to be an active admin key in the causally prior
profile state;
- every keychain operation ID to occur only once in the chain;
- each added admin key to have canonical key material matching its declared key
fingerprint; and
- causal add/revoke records rather than validity windows or payload timestamps
as authorization policy.
The root key seeds authorization at genesis only. A causally valid revocation
removes it like any other admin key.
To inspect an SSHSIGCHAIN JSONL transport file, pin the chain ID and root public
key locally:
```sh
geth keychain verify-sigchain \
--in geth.sshsigchain.v1.jsonl \
--chain-id <64-hex-character-chain-id> \
--root-key ~/.ssh/geth-root.pub
```
This verifier is experimental while geth adds its own record creation,
publication, import, accepted-head persistence, and independently generated
wire vectors. Those later workflows must preserve the same explicit trust
tuple; they must not introduce a compatibility route for the removed static
format.
## Local commands
Bootstrap an owner node:
```sh
geth init \
--admin-key ~/.ssh/id_ed25519_sk.pub \
--signing-key ~/.ssh/id_ed25519_sk \
--node-name laptop
```
Manage the current local keychain and its OpenSSH projection:
```sh
geth keychain admin-add \
--admin-key ~/.ssh/new_admin.pub \
--signing-key ~/.ssh/current_admin_sk \
--principal admin
geth keychain admin-revoke <key-fingerprint> \
--signing-key ~/.ssh/current_admin_sk
geth keychain allowed-signers --out allowed_signers
geth keychain sign-file --in authorized_keys --out authorized_keys.sig \
--signing-key ~/.ssh/id_ed25519_sk
geth keychain verify-file --in authorized_keys --signature authorized_keys.sig
geth keychain explain <op-id>
geth keychain explain-signer <key-id>
geth keychain verify
```
The keychain does not manage host `authorized_keys` policy. It can sign a
snapshot supplied by the operator, allowing another system to retain its own
SSH login policy while usefully checking approval against an active local admin
key.