Report keychain signature status

This commit is contained in:
Eric Wendland 2026-05-19 16:05:57 +02:00
commit 788522404d
7 changed files with 20 additions and 4 deletions

View file

@ -31,8 +31,9 @@ Most non-daemon commands talk to the daemon through a local Unix socket at
the keychain initialization/admin-key operations and signs their canonical
payloads through `ssh-keygen -Y sign` using the
`geth.keychain.v1@geth.local` namespace. This is the bootstrap path for
admin/YubiKey-rooted trust; signature verification for replicated keychain ops is
still future work.
admin/YubiKey-rooted trust. `geth keychain status` reports the number of stored
keychain signatures; signature verification for replicated keychain ops is still
future work.
The daemon can also install itself as a user service:

View file

@ -1102,6 +1102,7 @@ fn print_response(response: ControlResponse, json: bool) -> Result<()> {
ControlResponse::KeychainStatus(status) => {
println!("initialized: {}", status.initialized);
println!("admin_keys: {}", status.admin_keys);
println!("signatures: {}", status.signatures);
println!("users: {}", status.users);
println!("devices: {}", status.devices);
println!("nodes: {}", status.nodes);

View file

@ -592,6 +592,7 @@ pub struct NodeIdResponse {
pub struct KeychainStatusResponse {
pub initialized: bool,
pub admin_keys: usize,
pub signatures: usize,
pub users: usize,
pub devices: usize,
pub nodes: usize,

View file

@ -2914,6 +2914,7 @@ pub fn handle_request(
Ok(ControlResponse::KeychainStatus(KeychainStatusResponse {
initialized: view.initialized,
admin_keys: view.admin_keys.len(),
signatures: store.list_keychain_signatures()?.len(),
users: view.users.len(),
devices: view.devices.len(),
nodes: view.nodes.len(),

View file

@ -709,6 +709,7 @@ fn keychain_init_and_status_use_local_keychain_log() {
geth_control::ControlResponse::KeychainStatus(status) => {
assert!(status.initialized);
assert_eq!(status.admin_keys, 1);
assert_eq!(status.signatures, 0);
assert_eq!(status.users, 0);
}
other => panic!("unexpected response: {other:?}"),
@ -762,6 +763,15 @@ fn keychain_init_can_record_openssh_signatures() {
.list_keychain_signatures()
.expect("list signatures");
assert_eq!(signatures.len(), 2);
let response = geth_node::handle_request(&node, geth_control::ControlRequest::KeychainStatus)
.expect("keychain status");
match response {
geth_control::ControlResponse::KeychainStatus(status) => {
assert_eq!(status.signatures, 2);
}
other => panic!("unexpected response: {other:?}"),
}
}
#[test]

View file

@ -238,8 +238,9 @@ daemon persists local keychain init/admin-key operations and `keychain status`
reports the reduced local view. `keychain init --signing-key <path>` writes the
canonical keychain signing payloads, runs `ssh-keygen -Y sign` with the explicit
`geth.keychain.v1@geth.local` namespace, and stores the resulting OpenSSH
signatures in local SQLite. Verification and rejection of unsigned replicated
keychain operations are still future work.
signatures in local SQLite. `keychain status` reports the stored signature
count. Verification and rejection of unsigned replicated keychain operations are
still future work.
The authorization plane is `geth-auth`: resource-local signed operation logs,
grants, revocations, groups, and `auth explain`. Auth operations reduce into a

View file

@ -174,6 +174,7 @@ resource-scoped capability decisions.
- `[x]` OpenSSH keychain signatures use the explicit
`geth.keychain.v1@geth.local` namespace.
- `[x]` Keychain OpenSSH signatures are stored in local SQLite.
- `[x]` `geth keychain status` reports the stored keychain signature count.
- `[x]` Missing `ssh-keygen` or unavailable hardware keys produce clear
errors during signing.
- `[x]` Tests cover signed keychain init with a generated local OpenSSH key