host.access grant
on the host.
1. Register the user’s SSH public key
GET /keys lists them; DELETE /keys/{id} removes one.
Deleting a key does not erase its history — the fingerprint is denormalized into the SSH access log.
2. Grant host.access
"target_kind":"group") to grant access to every host in that
group, including hosts added later.
The grant recomputes the host’s snapshot and pushes it over the daemon’s live WebSocket
immediately. Offline hosts reconcile on their next connect.
3. Log in
custosd authkeys, which asks
the daemon for the authorized keys for that account.
Revoking
DELETE /grants/{id} revokes the grant and pushes a fresh snapshot — effective on the next login
attempt, not just the next reboot. Revocation is a soft delete, so the trail survives.
To cut a person off everywhere at once, suspend the user
(POST /users/{id}/suspend): that kills their sessions and pushes new snapshots to every affected
host. The snapshot query filters on active user status, which is what makes suspension cut SSH as
well as API access.
Troubleshooting
A connected daemon reportscached ssh keys: 0. Force a resync:
key_count. If that is 0, the control plane itself has no active
host.access grant plus matching public key for the host — the problem is the grant or the key, not
delivery.
Logins fail while the control plane is down. They should not. custosd authkeys retries the
daemon socket and then falls back to the last-known-good cache file on disk.
sshd is not calling Custos at all. Check the drop-in exists and sshd accepted it:
AuthorizedKeysCommandUser must be a real existing user.