Skip to main content
Access in Custos is grant-based. Admins grant; members exercise. A member with no grants can log in and see nothing.

Grants

A grant binds a user to one permission on one target:
target_kind is one of credential, host, group, set, backup, or global. target_id is null for global grants and required for every other kind. Grants are soft-revoked — revoking sets revoked_at rather than deleting the row, so the trail survives. A user may hold only one active grant per permission/target combination. Admins bypass grant resolution entirely.

Groups cascade

A group contains resources, not users. Granting a user a permission on a group cascades to every resource in it at resolve time, so adding a host to a group immediately extends existing group-targeted grants to that host.
Deleting a group revokes the grants that targeted it, in one transaction, and pushes fresh snapshots to the affected hosts.
Groups are groups of resources. Custos has no concept of a user group or team.

Global vs scoped permissions

Creation is global — there is no resource to scope it to yet. Everything else is scoped to a single resource, or to a group containing it.

How host.access reaches a host

Granting or revoking host.access recomputes the affected host’s authorized-key snapshot and pushes it immediately over the daemon’s live WebSocket — directly for a host target, fanned out for a group target. Offline hosts reconcile on their next connect.

User status

Suspending a user kills their sessions and pushes fresh snapshots, cutting SSH as well as API access. It is reversible. Removing a user deletes their login identities and revokes their grants and sessions, but keeps the user row, their keys, and their log entries so the audit trail stays readable.

Permission requests

A member without credential.read on a credential can request it (POST /credentials/{id}/permission-requests); an admin reviews it (PATCH /permission-requests/{id}). Approval creates the grant.