Skip to content

Users and bots

In Users you create people and bots, hand out the administrator role, and disable accounts. Each account has its own page, where most of what you do to it lives. Here's every operation and what it triggers.

Before you start

  • You're a kubelatch administrator.
  • Accounts are created from here, with kubelatch-server user create or, with OIDC login, by a domain rule or an approved join request (Domain access and join requests). Without a rule, a first sign-in only links an account that already exists. By default you share the links yourself over a secure channel; with Resend, kubelatch can e-mail them: see E-mailed invitations.
  • Logins are immutable and never reused, even after disabling the account. They're the identity clusters see: user:<login> for people, unless the cluster's identity template names them otherwise, and bot:<name> for bots.

Add a person

The Free edition allows 5 enabled people; the 6th invitation answers 422 edition.limit, and so does re-enabling someone at the limit. Bots are never limited. See Editions and license.

  1. In Users, click Create an account. The form opens in a panel on the right; leave Type as Person.
  2. Fill in Login (lowercase letters, digits, ., _ or -, 1 to 63 characters), Name and Email. Check Administrator if it applies.
  3. Click Create and invite.
  4. Copy the link from the dialog and share it over a secure channel. It isn't shown again.

With E-mailed invitations set up, the form asks how to deliver the invitation: Send by e-mail (to the address you typed, and you never see the link) or Copy the link, as above. After sending, a notice says it went out and when it expires.

The link looks like <KUBELATCH_BASE_URL>/account-link#kli_… and is valid for 72 hours; the dialog says until when. The token comes after the #, so it never reaches server or proxy logs. The /account-link page clears it from the address bar as soon as it's read: if the person reloads, they'll see Invalid link even though the original link still works.

What the person does with the link depends on the mode:

  • Without an external login: they set a password (12 to 128 characters, different from the login) and sign in.
  • With GitHub: they click Link with GitHub and sign in and authorize the App. They don't set any password. See GitHub login.
  • With an OIDC provider: they click Link with {name} and sign in and sign in at the provider; {name} is OIDC_DISPLAY_NAME. They don't set any password. Often they don't need the link at all: their first sign-in with Sign in with {name} links the account by its e-mail address, if the link policy allows it. See How accounts are linked.

With GitHub and OIDC both on, the link offers both buttons. A break-glass account also gets the password form.

Afterwards, grant them permissions in Permissions (Grant permissions), or add them to a group (Groups); the Access card of their page does both. They issue their credential in Home (Get a credential).

If the link is lost or expires, resend it by e-mail if that's how it went out, or generate another one from their page: Generate another link in the Sign-in card, or Reset access (without an external login) or Linking link (with GitHub or OIDC) in its menu. Generating a new one cancels that person's pending links.

The list and the account page

Users is the directory. A row has the account (its login, the name under it, a link to its page), Sign-in, Role, Access, Last activity and a menu with Open, Permissions, Requests and Disable (Enable on a disabled account). Last activity is the latest of its last sign-in, its last use of a credential and its last audited request. A sentence at the top counts every account (9 people and 3 bots; 3 administrators. 1 disabled account.), before anything narrows the list; a part at zero is left out. All, People, Bots and Disabled split the list, and Filter searches by login, name, email, GitHub account or the e-mail of the OIDC identity. Beside it, chips count the enabled accounts and filter the list: 3 administrators, 1 break-glass, 2 pending invitations (an invitation link nobody has used yet), 2 with no access (neither a group nor a direct permission), 3 linked to {name} (an identity of the OIDC provider, while it is on), 4 linked to GitHub (while GitHub is on) and 4 with a password (only with an external login on: without one, every person has a password). Press a chip to see those accounts, press several to combine them, and share the page's address, which keeps them. A chip with nothing to count isn't drawn. Pressing a chip takes the list back to All, and the tabs count what the chips leave. How accounts work unfolds a few lines of help and a link to this manual. With OIDC on, a line says whether kubelatch could read the provider's discovery document: {name}: discovery fetched {date}., {name}: discovery not fetched yet. or {name}: the last discovery fetch failed ({error}).

Home and Operations link here with the list already narrowed. With permissions and no activity in 90 days (enabled accounts created more than 90 days ago that hold a permission and have neither signed in nor made a request in 90 days, or ever) says so in a line above the list, with Clear filter; it adds to All, People, Bots or Disabled, to Filter and to the chips, which count the narrowed list. The invitations line of Pending (2 invitations expire this week) lands on the pending invitations chip, pressed, which holds every pending invitation.

Sign-in says in one pill how the account gets in: GitHub · alice, {name} · ana@acme.com (the provider's name and the e-mail of the OIDC identity), {name} · not signed in yet (OIDC on, no identity yet and no pending link), {name} · by domain and {name} · by request (an account a domain rule created, or a join request you approved), Password, Password · break-glass, Invitation · expires in 2 d, Invitation expired, Locked until 18:30, Disabled, or Credentials for a bot. An account linked to both GitHub and the OIDC provider shows its OIDC identity. A break-glass password and a pending invitation are tinted amber: the first bypasses GitHub and the OIDC provider, and the second is a link someone still has to use.

Click the login, or Open, for the account's page. At the top it names the account with its name, its kind (Person or Bot), Administrator if it is one, and the same pill. The Disable (or Enable) button and a menu hold the operations below; the menu offers only what applies to that account. Four figures say what it holds: Active permissions, Active credentials, Groups and Last activity. Then the cards: Access, across the full width (below), Sign-in (the method, when GitHub was linked, a row named after the OIDC provider with the e-mail it was linked as and when, whether it is break-glass, when the password last changed, a pending or expired link, and its sessions), Credentials, for a bot also CI rules and AI agent, and Activity: its last 20 requests, with Open in Audit for the rest.

The account's e-mail

The Sign-in card of the account's page shows its e-mail and where its notices go. They go to the e-mail of the account. Without one, and with OIDC login on, they go to the verified e-mail of its identity at the provider, and a line in the card says so. That address only delivers notices: it isn't copied to the account, so invitations and reset links still need an e-mail on the account. An account that signs in with GitHub gets notices once you give it an e-mail here.

Only an administrator changes it, from the account's page: Change opens the field, and Remove clears it. Nobody changes their own from My account, administrators included.

  • It takes a single address, such as ana@example.com, with no name and no list; anything else is 400 subject.email_invalid.
  • An address another account already has, enabled or not, as its own or as the e-mail of its OIDC identity, is refused with 409 subject.email_taken: both accounts' notices would reach one mailbox, and a sign-in with it would open the other account. Creating a person checks the same.
  • With OIDC login on and the link policy other than off, an address in one of the OIDC_ALLOWED_DOMAINS lets whoever signs in with that verified e-mail open this account and get its permissions, as soon as the account has no identity of the provider: now, or after an unlink. kubelatch asks you to confirm it first, also on an account that is linked today; through the API, the change answers 409 subject.email_autolinks until it carries "confirm_autolink": true. Creating a person with an address asks nothing: that is inviting it.
  • An address outside those domains is saved as it is: notices reach it, but it links no OIDC sign-in, and the field says so.
  • Changing or removing the address cancels the account's pending invitation or reset link that went out by e-mail, to the old address; a copied link stays. The notice after saving says so. The audit keeps user.update, with the address before and after, and account_link.revoke when it cancelled a link.

Both are the same item in the menu of the account's page, last 24 hours and are single use. Generating one immediately closes that person's sessions and cancels their pending links; it can't be generated for a disabled account:

Menu item When it shows up What it does
Reset access Without an external login, or on break-glass accounts Sets a new password, unlocks the account and closes previous sessions.
Linking link With GitHub or OIDC, on normal accounts Links the account to the GitHub account used to authorize, or to the identity the person signs in with at the OIDC provider, and closes previous sessions.

With E-mailed invitations, Reset access opens a dialog with the same two choices, an e-mail (24 hours) or a link to copy, and asks for confirmation because it closes the person's sessions. A row with an invitation sent by e-mail reads E-mailed invitation · expires in 2 d and its menu offers Resend invitation by e-mail and Copy a new link; either cancels the previous one.

Specific cases (forgotten password, locked account, changed GitHub account, wrong OIDC identity) are in Accounts and recovery.

Access

The Access column says what each account holds: how many groups it's a member of and how many direct permissions it has, for example 2 groups · 1 direct. Expired memberships and permissions don't count. The cell opens Permissions in By account on that account. An account with neither shows no access.

The account's page has an Access card. First come its groups, one line each, such as Member of Backend, linked to the group's page, with the expiry of the membership and a menu with Extend membership and Remove from Backend. Under them, every permission in force by cluster, direct or through a group, so the list matches the Active permissions figure. Each is a permission line with its menu and its checkbox (Read a permission).

The Access card of alice's page: her membership of Backend with its expiry, then her permissions on prod and staging, direct and via Backend.

These items work on access:

Item What it does
Permissions, in the row menu, and See in Permissions, in the card Opens Permissions in By account on that account, like the Access cell (By account).
Grant permissions, in the card Opens Permissions with the grant panel open and the account already chosen (Grant a permission).
Add to a group, in the card Opens a panel with Group (only the groups the account isn't in yet) and Membership expires (Never by default). Add makes the account a member: it receives the group's permissions at once (Groups).

A disabled account keeps both lists, with no menu or checkbox, and isn't offered the last two items. Its permissions are dimmed and count for nothing, so the figure leaves them out.

Disable and enable

Disable, the button on the account's page or the item in its row menu in Users (person or bot), after confirming:

  • Revokes all their credentials instantly: the next request gets a 401 and open exec or watch sessions are cut within 10 s.
  • Closes their sessions and cancels their pending links.
  • On the next reconciliation, removes them from the list of subjects the proxy can impersonate on each cluster.

Their permissions and group memberships are kept, but don't count while they're disabled. Enable puts them back on the clusters without granting anything again. It doesn't bring back credentials or links: you have to issue or generate new ones.

To disable several at once, tick them in Users (under All, People or Bots; your own account and the disabled ones can't be ticked) and choose Disable N in the bar. The confirmation lists each account with what it loses and takes an optional reason, kept in the control log. It's all or nothing, up to 500 at once: a batch that would leave no administrator able to sign in is refused, names the account and changes nothing. An account already disabled counts as done. The seats the edition counts free up at once.

The interface won't let you disable yourself (the API will, unless you're the last administrator who can sign in). When someone leaves the company, disable them the same day. With GitHub, removing them from the organization is enough: see GitHub login. With OIDC, disabling them in the provider is not: it only stops their next sign-in, and their web session, CLI session and credentials last until they expire (Identity with an OIDC provider).

Subjects are never deleted: disabling is how you retire them.

Administrators

The Role column says Administrator for those who are. The account's page grants or removes the role in its menu, with Make administrator or Remove administrator; both ask for confirmation. The menu offers the first only for an enabled account, so a disabled administrator can still be demoted. The interface won't let you change your own role (the API will, unless you're the last administrator who can sign in). Creating a person with Administrator ticked says what that means: they can grant any access, issue credentials for anyone and manage accounts. An administrator sees, in the sidebar, Permissions, Users, Groups, Roles and Credentials under Access, Audit under Record, and Clusters and CI under Platform, and Notices in the top bar.

kubelatch prevents removing the role, disabling, unlinking from GitHub or from the OIDC provider, or unmarking as break-glass for the last administrator who can sign in, and responds 409. "Can sign in" means: with a password, or, with GitHub or OIDC on, with a break-glass password, with GitHub linked while GitHub is on, or with an identity of the configured OIDC provider while OIDC is on.

Sign out web sessions

Sign out web sessions, in the menu of the account's page or in its Sign-in card, closes all of that person's web sessions instantly, after confirming. It doesn't revoke their credentials, and it leaves their CLI sessions open, which are credentials too: for those, use Revoke in Credentials or disable them. The Sign-in card counts the CLI sessions open; web sessions are signed cookies the server doesn't list, so it can't count them.

With GitHub on, Unlink GitHub, in the menu of the account's page, separates the account from its GitHub account and closes its sessions. Until it's linked again with a Linking link, it can only sign in as a break-glass account, or through the OIDC provider if it has an identity there.

Use it when someone linked the wrong GitHub account, or when linking returns github_taken (that GitHub account is already linked to someone else).

With OIDC on, Unlink {name}, in the menu of the account's page, removes the account's OIDC identity and closes its sessions, after confirming in Unlink "ana@acme.com" from "ana". The notice reads {name} unlinked from "ana". The menu offers it only to an account linked to the configured provider. Its next sign-in with {name} links an identity again by e-mail, if the link policy allows it; otherwise, generate a Linking link.

Use it when:

  • the person the account belongs to gets identity_mismatch because their account at the provider was recreated. If instead its e-mail address now belongs to someone else, don't unlink: the account is still its previous owner's, so disable it and create one for the newcomer (When someone leaves, or an address comes back);
  • linking returns oidc_taken: that identity already opens another kubelatch account, which you unlink first;
  • the account was linked to the wrong person: check the e-mail in Audit (oidc.link) before unlinking.

Unlinking doesn't revoke credentials or CLI sessions: to cut everything, disable the account. How accounts are linked is in OIDC login (SSO).

Bots

A bot is a subject with no password or session: it only has credentials. It's for CI, Argo CD and any automation.

  1. In Users, click Create an account and choose Type → Bot (CI, Argo CD…).
  2. Put the name in Login (lowercase letters, digits and dashes, 1 to 63 characters) and, if you want, a descriptive Name.
  3. Click Create bot. The notice offers Open its page.
  4. Grant it permissions in Permissions, or add it to a group, like any subject.

There are two ways to give it credentials:

  • From GitHub Actions, with no secrets: a trust rule in CI (CI: trust rules); the CI rules card of the bot's page lists its rules and starts a new one.
  • By hand: in Credentials, or in the Credentials card of the bot's page, click Issue a credential, pick the bot in Account (already chosen from its page), set Name (required), Duration and, if you want, a Cluster and a Note (optional), and click Issue credential. Duration starts at the shortest one offered, and a line under the form says what you're about to issue. The token and the kubeconfig are shown only once. Every credential expires: for a bot, at most after 90 days (KUBELATCH_MAX_TTL_BOT).

Save the kubeconfig in the secret manager of whatever tool uses it and note its expiry on your calendar. Credentials lists the nearest expiry first and colours it amber with 7 days or less left, red with under 24 hours; the sidebar marks Credentials with the same counts, as Permissions does. CLI sessions are replaced by the next kubelatch login and GitHub Actions credentials are reissued on every run, so neither the marks nor the expires today and this week chips count them. Issuing a credential requires the bot to have at least one active permission.

For an AI agent, the bot's page has an AI agent card: the Writes need approval switch (whether its writes wait for an administrator's approval; changing it asks first), Connect an agent, with the commands to connect it, and Sessions of this bot (AI agents).

A compromised bot: revoke its credentials in Credentials or disable it, which revokes all of them and removes it from the clusters. Reset access and Sign out web sessions don't apply to bots: their page has no menu, only Disable.

Find, read and revoke credentials

Credentials lists every credential issued, in Active, Expired and Revoked. A sentence at the top counts them (18 active credentials of 7 accounts. 2 revoked in the last 30 days.), and chips count the active ones and filter the list: 1 expires today and 3 this week (credentials that end within 24 hours or within 7 days, as the sidebar counts them: never a CLI session or a CI token), 5 CLI sessions, 2 unused in 30 days and 4 of bots. Press a chip to see what it counts, press several to combine them, and share the page's address, which keeps them; a chip with nothing to count isn't drawn, and pressing one takes the list back to Active. Filter searches by login, name, prefix, cluster or a whole token. A row says its account, its name with its prefix and kind (CLI session, or CI token · run 1234 · alice), what it reaches, who issued it when it wasn't the account itself, when it expires and when it was last used. A credential with no cluster follows its account: Reach reads, for example, 2 clusters: kind-local · prod, or no cluster yet while the account has no active permission.

Revoke is in the row of every active credential. It asks for a reason, optional, and cuts the access right away: the next request gets 401 and open streams are cut within 10 s.

The name opens the credential's detail in a panel: Account, Kind, Status (for a revoked one, when, by whom and why), Issued, Prefix and Note; Reach, with the account's role and scope on each cluster it reaches; and Use, read from the audit: Last used, Last IP, Last user agent and Requests in 24 h. At the foot, Revoke (while it's active) and Requests, which opens Audit with only that credential. The row menu offers View details and Requests. A link from another page can narrow the list to an account, a kind or a cluster: a line above says so (Only: …), with Show all. The figures on Home also link here, with the matching chips pressed: Unused in 30 days presses unused in 30 days (active credentials not used in the last 30 days, or never used and created more than 30 days ago), and the bots' credentials that end today press of bots and expires today together (standard credentials with under 24 hours left: never CLI sessions or CI tokens, which renew themselves). A pressed chip keeps the list on Active, and Clear under an empty result lifts them.

Find a leaked token

Paste the whole token in Filter. kubelatch looks it up on the server and opens that credential's detail, also if it has already expired or been revoked (with when, by whom and why), or answers no credential of this instance matches that token. It works for the token of an AI agent's session too, which no list shows: its Kind reads AI agent session. The token travels in a request body, never in a URL, and kubelatch neither stores nor logs it: the control plane only records that someone looked one up and whether it matched (The control plane), with a limit of 10 lookups per minute per IP. A shorter piece, like the prefix, only narrows the list.

Via the API

Everything above exists in the JSON API too, for example POST /api/subjects (with "kind":"bot" for a bot), POST /api/subjects/<id>/disable (POST /api/subjects/disable for several), /enable, /logout and /reset-link, and DELETE /api/subjects/<id>/github or /oidc. The full list is in HTTP API.